int SendDataBuff(byte[] data, int startIndex, int size, Data_Info_s pPacker) { try { int sendedCount = 0; if (pPacker != null && pPacker.sendSOcket != null) { //var start = DateTime.Now; sendedCount = pPacker.sendSOcket.SendTo(data, startIndex, size, SocketFlags.None, pPacker.remotePoint); //if (sendedCount != 12) // Console.WriteLine(sendedCount); //Thread.Sleep(40); //Thread.Sleep(40); //var end = DateTime.Now.Subtract(start).Milliseconds; //Console.WriteLine("send audio to soldier " + end); } return(sendedCount); } catch (Exception ex) { Console.WriteLine(ex.Message + ex.StackTrace); return(0); } }
/*** *@remark: 音视频数据的打包成ps流,并封装成rtp *@param : pData [in] 需要发送的音视频数据 * nFrameLen [in] 发送数据的长度 * pPacker [in] 数据包的一些信息,包括时间戳,rtp数据buff,发送的socket相关信息 * stream_type[in] 数据类型 0 视频 1 音频 *@return: 0 success others failed */ public int Gb28181_streampackageForH264(byte[] pData, int nFrameLen, Data_Info_s pPacker, int stream_type) { try { byte[] szTempPacketHead = new byte[PS_HDR_LEN + SYS_HDR_LEN + PSM_HDR_LEN]; int nSizePos = 0; int nSize = 0; byte[] pBuff = null; Array.Clear(szTempPacketHead, 0, szTempPacketHead.Length); // 1 package for ps header Gb28181_make_ps_header(szTempPacketHead, nSizePos, pPacker.s64CurPts); nSizePos += PS_HDR_LEN; //2 system header //if (pPacker.IFrame == 1) //{ // 如果是I帧的话,则添加系统头 Gb28181_make_sys_header(szTempPacketHead, nSizePos); nSizePos += SYS_HDR_LEN; //这个地方我是不管是I帧还是p帧都加上了map的,貌似只是I帧加也没有问题 // gb28181_make_psm_header(szTempPacketHead + nSizePos); // nSizePos += PSM_HDR_LEN; //} // 3 psm头 (也是map) Gb28181_make_psm_header(szTempPacketHead, nSizePos); nSizePos += PSM_HDR_LEN; //加上rtp发送出去,这样的话,后面的数据就只要分片分包就只有加上pes头和rtp头了 //if (gb28181_send_rtp_pack(szTempPacketHead, 0, nSizePos, 0, pPacker) != 0) // return -1; // 这里向后移动是为了方便拷贝pes头 //这里是为了减少后面音视频裸数据的大量拷贝浪费空间,所以这里就向后移动,在实际处理的时候,要注意地址是否越界以及覆盖等问题 pBuff = new byte[szTempPacketHead.Length + pData.Length + PES_HDR_LEN]; Array.Copy(szTempPacketHead, pBuff, szTempPacketHead.Length); Array.Copy(pData, 0, pBuff, szTempPacketHead.Length + PES_HDR_LEN, pData.Length); int startIndex = 0; //含有有效数据 // bHasPayload = true; while (nFrameLen > 0) { //每次帧的长度不要超过short类型,过了就得分片进循环行发送 nSize = (nFrameLen > PS_PES_PAYLOAD_SIZE) ? PS_PES_PAYLOAD_SIZE : nFrameLen; // 添加pes头 Gb28181_make_pes_header(pBuff, szTempPacketHead.Length, stream_type == 1 ? 0xC0 : 0xE0, nSize, (pPacker.s64CurPts / 1), (pPacker.s64CurPts / 3)); //最后在添加rtp头并发送数据 if (Gb28181_send_rtp_pack(pBuff, startIndex, szTempPacketHead.Length + nSize + PES_HDR_LEN, ((nSize == nFrameLen) ? 1 : 0), pPacker) != 0) { Console.WriteLine("gb28181_send_pack failed!\n"); return(-1); } //分片后每次发送的数据移动指针操作 nFrameLen -= nSize; //这里也只移动nSize,因为在while向后移动的pes头长度,正好重新填充pes头数据 startIndex += nSize; } // bHasPayload = false; } catch (Exception ex) { Console.WriteLine(ex.Message + ex.StackTrace); } return(0); }
int Gb28181_send_rtp_pack(byte[] databuff, int index, int nDataLen, int mark_flag, Data_Info_s pPacker) { try { int nRet = 0; int nPlayLoadLen = 0; int nSendSize = 0; byte[] szRtpHdr = new byte[RTP_HDR_LEN]; Array.Clear(szRtpHdr, 0, RTP_HDR_LEN); if (nDataLen + RTP_HDR_LEN <= RTP_MAX_PACKET_BUFF)// 1460 pPacker指针本来有一个1460大小的buffer数据缓存 { // 一帧数据发送完后,给mark标志位置1 Gb28181_make_rtp_header(szRtpHdr, 0, ((mark_flag == 1) ? 1 : 0), ++pPacker.u16CSeq, (pPacker.s64CurPts / 1), pPacker.u32Ssrc); Array.Copy(szRtpHdr, pPacker.szBuff, RTP_HDR_LEN); Array.Copy(databuff, index, pPacker.szBuff, RTP_HDR_LEN, nDataLen); nRet = SendDataBuff(pPacker.szBuff, 0, RTP_HDR_LEN + nDataLen, pPacker);//ZXB: 发送数据 为什么加databuff参数 需不需要加上index if (nRet != (RTP_HDR_LEN + nDataLen)) { Console.WriteLine(" udp send error !\n"); return(-1); } //录制mf //outputData(pPacker.szBuff, 0, RTP_HDR_LEN + nDataLen, bHasPayload, true, true); } else { nPlayLoadLen = RTP_MAX_PACKET_BUFF - RTP_HDR_LEN; // 每次只能发送的数据长度 除去rtp头 Gb28181_make_rtp_header(pPacker.szBuff, 0, 0, ++pPacker.u16CSeq, (pPacker.s64CurPts / 1), pPacker.u32Ssrc); //memcpy(pPacker->szBuff + RTP_HDR_LEN, databuff, nPlayLoadLen); Array.Copy(databuff, index, pPacker.szBuff, RTP_HDR_LEN, nPlayLoadLen); nRet = SendDataBuff(pPacker.szBuff, 0, RTP_HDR_LEN + nPlayLoadLen, pPacker);//ZXB: 发送数据 为什么加databuff参数需不需要加上index if (nRet != (RTP_HDR_LEN + nPlayLoadLen)) { Console.WriteLine(" udp send error !\n"); return(-1); } //录制mf //outputData(pPacker.szBuff, 0, RTP_HDR_LEN + nPlayLoadLen, bHasPayload, true, true); nDataLen -= nPlayLoadLen; index += nPlayLoadLen; // 表明前面到数据已经发送出去 index -= RTP_HDR_LEN; // 用来存放rtp头 while (nDataLen > 0) { if (nDataLen <= nPlayLoadLen) { //一帧数据发送完,置mark标志位 Gb28181_make_rtp_header(databuff, index, mark_flag, ++pPacker.u16CSeq, (pPacker.s64CurPts / 1), pPacker.u32Ssrc); nSendSize = nDataLen; } else { Gb28181_make_rtp_header(databuff, index, 0, ++pPacker.u16CSeq, (pPacker.s64CurPts / 1), pPacker.u32Ssrc); nSendSize = nPlayLoadLen; } nRet = SendDataBuff(databuff, index, RTP_HDR_LEN + nSendSize, pPacker);//ZXB: 发送数据 为什么加databuff参数需不需要加上index if (nRet != (RTP_HDR_LEN + nSendSize)) { Console.WriteLine(" udp send error !\n"); return(-1); } //录制mf //outputData(databuff, index, RTP_HDR_LEN + nSendSize, bHasPayload, true, false); nDataLen -= nSendSize; index += nSendSize; //因为buffer指针已经向后移动一次rtp头长度后, //所以每次循环发送rtp包时,只要向前移动裸数据到长度即可,这是buffer指针实际指向到位置是 //databuff向后重复的rtp长度的裸数据到位置上 } } } catch (Exception ex) { Console.WriteLine(ex.Message + ex.StackTrace); } return(0); }