上一节编写了注册流程以及交互部分程序,这一节来进行程序调用以及发送视频流部分的程序编写
发送视频流部分程序
- 发送视频流部分代码部分使用的QuickGBLink的在此基础上进行了部分修改
- 链接如下:(27条消息) 国标PS流打包和RTP发送代码_QuickGBLink的博客-CSDN博客_rtp发送代码
rtpsend.h
#ifndef RTPSEND_H
#define RTPSEND_H
#include <stdint.h>
#define TRACE(a,...) printf(" DEBUG :%s(%d)-<%s>: %s\r\n",__FILE__, __LINE__, __FUNCTION__,a)
//#include <stdint.h>
typedef unsigned int uint32_t;
typedef unsigned long int uint64_t;
#define PS_HDR_LEN 14
#define SYS_HDR_LEN 18
#define PSM_HDR_LEN 24
#define PES_HDR_LEN 19
#define PS_SYS_MAP_SIZE 30
#define PS_PES_PAYLOAD_SIZE (65535 - PES_HDR_LEN)
#define RTP_HDR_LEN 12
#define RTP_HDR_SIZE 12 // ?
#define RTP_MAX_PACKET_BUFF 1300
#define RTP_VERSION 2//?
struct bits_buffer_s
{
int i_size;
int i_data;
int i_mask;
unsigned char * p_data;
};
struct Data_Info_s
{
char dstIP[32];
int nPort;
uint32_t sCurPts;
int IFrame;
unsigned short u16CSeq;
unsigned int u32Ssrc;
char szBuff[RTP_MAX_PACKET_BUFF];
};
#define MAX_RES_BUF 512000 //512*1024
#define MAX_RTP_CHANNEL 8
class rtpSend
{
protected:
int makePsHeader(char *pData, uint64_t s64Scr);
int makeSysHeader(char *pData);
int makePsmHeader(char *pData);
int makePesHeader(char *pData, int stream_id, int payload_len, unsigned long long pts, unsigned long long dts);
int sendDataByUDP(int nChn,char* databuff, int nLen);
int makeRtpHeader(char *pData, int marker_flag, unsigned short cseq, long long curpts, unsigned int ssrc);
int sendRtpPacket(int nChn,char *databuff, int nDataLen, int mark_flag, Data_Info_s* pPacker);
void SaveSpsPps(int nChn,char *pBuf, int nLen, int type);
public:
static rtpSend *createNew();
rtpSend();
~rtpSend();
void SetSSRC(int nChn, int nSsc);
void SetRemoteAddr(int nChn,char* ip, int nPort); //设置目标发送地址
int GetOneIdleChan(); //获得一个空闲的通道
int SendH264Stream(int nChn,char *pData, int nFrameLen, uint32_t curPts, int frameType);
int SendPSStream(int nChn, char *pData, int nFrameLen, uint32_t sCurPts, int mark_flag);
int rtpSendPort(int nChn) {return m_rtpSendPort[nChn];}
int OpenStream(int nChn);
void CloseStream(int nChn);
bool IsStreamOpen(int nChn);
void SetWritable(int nChn, bool bWrite);
bool IsWritable(int nChn);
private:
int m_sock[MAX_RTP_CHANNEL];
int m_rtpSendPort[MAX_RTP_CHANNEL];
Data_Info_s m_DataInfo[MAX_RTP_CHANNEL];
char* m_pResBuf[MAX_RTP_CHANNEL];
char* m_pPps[MAX_RTP_CHANNEL];
char* m_pSps[MAX_RTP_CHANNEL];
int m_nSps[MAX_RTP_CHANNEL];
int m_nPps[MAX_RTP_CHANNEL];
bool m_bOpenStream[MAX_RTP_CHANNEL];
bool m_bWaitIFrame[MAX_RTP_CHANNEL];
bool m_bCanWrite[MAX_RTP_CHANNEL];
};
#endif // RTPSEND_H
rtpsend.cpp
//#include "stdafx.h"
#include "rtpsend.h"
#include <stdlib.h>
#include <stdio.h>
#include <memory>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <assert.h>
//#include <atlbase.h>
#define bits_write(buffer, count, bits)\
{\
bits_buffer_s *p_buffer = (buffer);\
int i_count = (count);\
uint64_t i_bits = (bits);\
while( i_count > 0 )\
{\
i_count--;\
if( ( i_bits >> i_count )&0x01 )\
{\
p_buffer->p_data[p_buffer->i_data] |= p_buffer->i_mask;\
}\
else\
{\
p_buffer->p_data[p_buffer->i_data] &= ~p_buffer->i_mask;\
}\
p_buffer->i_mask >>= 1; /*操作完一个字节第一位后,操作第二位*/\
if( p_buffer->i_mask == 0 ) /*循环完一个字节的8位后,重新开始下一位*/\
{\
p_buffer->i_data++;\
p_buffer->i_mask = 0x80;\
}\
}\
}
//FILE *fp;
rtpSend *
rtpSend::createNew(){
rtpSend *mRtpSend = new rtpSend;
//fp = fopen("my_h264.711a", "wb");
if (mRtpSend == NULL) {
TRACE("mRtpSend new NONO");
return NULL;
}
return mRtpSend;
}
rtpSend::rtpSend()
{
for (int i = 0; i < MAX_RTP_CHANNEL; i++)
{
int on = 1;
m_sock[i] = socket(AF_INET, SOCK_DGRAM, 0);
setsockopt(m_sock[i], SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on));
m_rtpSendPort[i] = 6666 + i;
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_port = htons(m_rtpSendPort[i]);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(m_sock[i], (struct sockaddr* )&addr, sizeof(addr)))
{
TRACE("bind error\n");
}
m_pResBuf[i] = new char[MAX_RES_BUF] ;
m_pPps[i] = new char[1024];
m_pSps[i] = new char[1024];
m_nSps[i] = 0;
m_nPps[i] = 0;
m_DataInfo[i].sCurPts = 0;
m_bOpenStream[i] = false;
m_bCanWrite[i] = false;
}
}
rtpSend::~rtpSend()
{
for (int i = 0; i < MAX_RTP_CHANNEL; i++)
{
delete[] m_pResBuf[i];
delete[] m_pPps[i];
delete[] m_pSps[i];
close(m_sock[i]);
}
}
int rtpSend::OpenStream(int nChn)
{
TRACE("open stream %d\n", nChn);
m_bOpenStream[nChn] = true;
m_bWaitIFrame[nChn] = true;
m_DataInfo[nChn].sCurPts = 0;
m_DataInfo[nChn].u16CSeq = 0;
return true;
}
void rtpSend::CloseStream(int nChn)
{
TRACE("close stream %d\n", nChn);
m_bOpenStream[nChn] = false;
m_bCanWrite[nChn] = false;
}
bool rtpSend::IsStreamOpen(int nChn)
{
return m_bOpenStream[nChn];
}
void rtpSend::SetWritable(int nChn, bool bWrite)
{
m_bCanWrite[nChn] = bWrite;
}
bool rtpSend::IsWritable(int nChn)
{
return m_bCanWrite[nChn];
}
int rtpSend::makePsHeader(char *pData, uint64_t currPts)
{
unsigned long long lScrExt = (currPts) % 100;
unsigned long long s64Scr = currPts / 100;
// 这里除以100是由于sdp协议返回的video的频率是90000,帧率是25帧/s,所以每次递增的量是3600,
// 所以实际你应该根据你自己编码里的时间戳来处理以保证时间戳的增量为3600即可,
//如果这里不对的话,就可能导致卡顿现象了
bits_buffer_s bitsBuffer;
bitsBuffer.i_size = PS_HDR_LEN;
bitsBuffer.i_data = 0;
bitsBuffer.i_mask = 0x80; // 二进制:10000000 这里是为了后面对一个字节的每一位进行操作,避免大小端夸字节字序错乱
bitsBuffer.p_data = (unsigned char *)(pData);
memset(bitsBuffer.p_data, 0, PS_HDR_LEN);
bits_write(&bitsBuffer, 32, 0x000001BA); /*start codes*/
bits_write(&bitsBuffer, 2, 1); /*marker bits '01b'*/
bits_write(&bitsBuffer, 3, (s64Scr >> 30) & 0x07); /*System clock [32..30]*/
bits_write(&bitsBuffer, 1, 1); /*marker bit*/
bits_write(&bitsBuffer, 15, (s64Scr >> 15) & 0x7FFF); /*System clock [29..15]*/
bits_write(&bitsBuffer, 1, 1); /*marker bit*/
bits_write(&bitsBuffer, 15, s64Scr & 0x7fff); /*System clock [29..15]*/
bits_write(&bitsBuffer, 1, 1); /*marker bit*/
bits_write(&bitsBuffer, 9, lScrExt & 0x01ff); /*System clock [14..0]*/
bits_write(&bitsBuffer, 1, 1); /*marker bit*/
bits_write(&bitsBuffer, 22, (255) & 0x3fffff); /*bit rate(n units of 50 bytes per second.)*/
bits_write(&bitsBuffer, 2, 3); /*marker bits '11'*/
bits_write(&bitsBuffer, 5, 0x1f); /*reserved(reserved for future use)*/
bits_write(&bitsBuffer, 3, 0); /*stuffing length*/
return 0;
}
int rtpSend::makeRtpHeader(char *pData, int marker_flag, unsigned short cseq, long long curpts, unsigned int ssrc)
{
bits_buffer_s bitsBuffer;
if (pData == NULL)
return -1;
bitsBuffer.i_size = RTP_HDR_LEN;
bitsBuffer.i_data = 0;
bitsBuffer.i_mask = 0x80;
bitsBuffer.p_data = (unsigned char *)(pData);
memset(bitsBuffer.p_data, 0, RTP_HDR_SIZE);
bits_write(&bitsBuffer, 2, RTP_VERSION); /* rtp version */
bits_write(&bitsBuffer, 1, 0); /* rtp padding */
bits_write(&bitsBuffer, 1, 0); /* rtp extension */
bits_write(&bitsBuffer, 4, 0); /* rtp CSRC count */
bits_write(&bitsBuffer, 1, (marker_flag)); /* rtp marker */
bits_write(&bitsBuffer, 7, 96); /* rtp payload type*/
bits_write(&bitsBuffer, 16, (cseq)); /* rtp sequence */
bits_write(&bitsBuffer, 32, (curpts)); /* rtp timestamp */
bits_write(&bitsBuffer, 32, (ssrc)); /* rtp SSRC */
return 0;
}
int rtpSend::makeSysHeader(char *pData)
{
bits_buffer_s bitsBuffer;
bitsBuffer.i_size = SYS_HDR_LEN;
bitsBuffer.i_data = 0;
bitsBuffer.i_mask = 0x80;
bitsBuffer.p_data = (unsigned char *)(pData);
memset(bitsBuffer.p_data, 0, SYS_HDR_LEN);
/*system header*/
bits_write(&bitsBuffer, 32, 0x000001BB); /*start code*/
bits_write(&bitsBuffer, 16, SYS_HDR_LEN - 6);/*header_length 表示次字节后面的长度,后面的相关头也是次意思*/
bits_write(&bitsBuffer, 1, 1); /*marker_bit*/
bits_write(&bitsBuffer, 22, 50000); /*rate_bound*/
bits_write(&bitsBuffer, 1, 1); /*marker_bit*/
bits_write(&bitsBuffer, 6, 1); /*audio_bound*/
bits_write(&bitsBuffer, 1, 0); /*fixed_flag */
bits_write(&bitsBuffer, 1, 1); /*CSPS_flag */
bits_write(&bitsBuffer, 1, 1); /*system_audio_lock_flag*/
bits_write(&bitsBuffer, 1, 1); /*system_video_lock_flag*/
bits_write(&bitsBuffer, 1, 1); /*marker_bit*/
bits_write(&bitsBuffer, 5, 1); /*video_bound*/
bits_write(&bitsBuffer, 1, 0); /*dif from mpeg1*/
bits_write(&bitsBuffer, 7, 0x7F); /*reserver*/
/*audio stream bound*/
bits_write(&bitsBuffer, 8, 0xC0); /*stream_id*/
bits_write(&bitsBuffer, 2, 3); /*marker_bit */
bits_write(&bitsBuffer, 1, 0); /*PSTD_buffer_bound_scale*/
bits_write(&bitsBuffer, 13, 512); /*PSTD_buffer_size_bound*/
/*video stream bound*/
bits_write(&bitsBuffer, 8, 0xE0); /*stream_id*/
bits_write(&bitsBuffer, 2, 3); /*marker_bit */
bits_write(&bitsBuffer, 1, 1); /*PSTD_buffer_bound_scale*/
bits_write(&bitsBuffer, 13, 2048); /*PSTD_buffer_size_bound*/
return 0;
}
int rtpSend::sendDataByUDP(int nChn, char* databuff, int nLen)
{
// TRACE("sendDataByUDP %s:%d\n", m_DataInfo[nChn].dstIP, m_DataInfo[nChn].nPort);
struct sockaddr_in addrSrv;
addrSrv.sin_addr.s_addr = inet_addr(m_DataInfo[nChn].dstIP);
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(m_DataInfo[nChn].nPort);
int sendRet = sendto(m_sock[nChn], databuff, nLen, 0,
(struct sockaddr*)&addrSrv, sizeof(sockaddr));
return sendRet;
}
int rtpSend::makePsmHeader(char *pData)
{
bits_buffer_s bitsBuffer;
bitsBuffer.i_size = PSM_HDR_LEN;
bitsBuffer.i_data = 0;
bitsBuffer.i_mask = 0x80;
bitsBuffer.p_data = (unsigned char *)(pData);
memset(bitsBuffer.p_data, 0, PS_SYS_MAP_SIZE);
bits_write(&bitsBuffer, 24, 0x000001); /*start code*/
bits_write(&bitsBuffer, 8, 0xBC); /*map stream id*/
bits_write(&bitsBuffer, 16, 18); /*program stream map length*/
bits_write(&bitsBuffer, 1, 1); /*current next indicator */
bits_write(&bitsBuffer, 2, 3); /*reserved*/
bits_write(&bitsBuffer, 5, 0); /*program stream map version*/
bits_write(&bitsBuffer, 7, 0x7F); /*reserved */
bits_write(&bitsBuffer, 1, 1); /*marker bit */
bits_write(&bitsBuffer, 16, 0); /*programe stream info length*/
bits_write(&bitsBuffer, 16, 8); /*elementary stream map length is*/
/*audio*/
bits_write(&bitsBuffer, 8, 0x90); /*stream_type*/
bits_write(&bitsBuffer, 8, 0xC0); /*elementary_stream_id*/
bits_write(&bitsBuffer, 16, 0); /*elementary_stream_info_length is*/
/*video*/
bits_write(&bitsBuffer, 8, 0x1B); /*stream_type*/
bits_write(&bitsBuffer, 8, 0xE0); /*elementary_stream_id*/
bits_write(&bitsBuffer, 16, 0); /*elementary_stream_info_length */
/*crc (2e b9 0f 3d)*/
bits_write(&bitsBuffer, 8, 0x45); /*crc (24~31) bits*/
bits_write(&bitsBuffer, 8, 0xBD); /*crc (16~23) bits*/
bits_write(&bitsBuffer, 8, 0xDC); /*crc (8~15) bits*/
bits_write(&bitsBuffer, 8, 0xF4); /*crc (0~7) bits*/
return 0;
}
int rtpSend::makePesHeader(char *pData, int stream_id, int payload_len, unsigned long long pts, unsigned long long dts)
{
bits_buffer_s bitsBuffer;
bitsBuffer.i_size = PES_HDR_LEN;
bitsBuffer.i_data = 0;
bitsBuffer.i_mask = 0x80;
bitsBuffer.p_data = (unsigned char *)(pData);
memset(bitsBuffer.p_data, 0, PES_HDR_LEN);
/*system header*/
bits_write(&bitsBuffer, 24, 0x000001); /*start code*/
bits_write(&bitsBuffer, 8, (stream_id)); /*streamID*/
bits_write(&bitsBuffer, 16, (payload_len)+8); /*packet_len*/ //指出pes分组中数据长度和该字节后的长度和
bits_write(&bitsBuffer, 2, 2); /*'10'*/
bits_write(&bitsBuffer, 2, 0); /*scrambling_control*/
bits_write(&bitsBuffer, 1, 0); /*priority*/
bits_write(&bitsBuffer, 1, 0); /*data_alignment_indicator*/
bits_write(&bitsBuffer, 1, 0); /*copyright*/
bits_write(&bitsBuffer, 1, 0); /*original_or_copy*/
bits_write(&bitsBuffer, 1, 1); /*PTS_flag*/
bits_write(&bitsBuffer, 1, 0); /*DTS_flag*/
bits_write(&bitsBuffer, 1, 0); /*ESCR_flag*/
bits_write(&bitsBuffer, 1, 0); /*ES_rate_flag*/
bits_write(&bitsBuffer, 1, 0); /*DSM_trick_mode_flag*/
bits_write(&bitsBuffer, 1, 0); /*additional_copy_info_flag*/
bits_write(&bitsBuffer, 1, 0); /*PES_CRC_flag*/
bits_write(&bitsBuffer, 1, 0); /*PES_extension_flag*/
bits_write(&bitsBuffer, 8, 5); /*header_data_length*/
// 指出包含在 PES 分组标题中的可选字段和任何填充字节所占用的总字节数。该字段之前
//的字节指出了有无可选字段。
/*PTS,DTS*/
bits_write(&bitsBuffer, 4, 3); /*'0011'*/
bits_write(&bitsBuffer, 3, ((pts) >> 30) & 0x07); /*PTS[32..30]*/
bits_write(&bitsBuffer, 1, 1);
bits_write(&bitsBuffer, 15, ((pts) >> 15) & 0x7FFF); /*PTS[29..15]*/
bits_write(&bitsBuffer, 1, 1);
bits_write(&bitsBuffer, 15, (pts) & 0x7FFF); /*PTS[14..0]*/
bits_write(&bitsBuffer, 1, 1);
#if 0
bits_write(&bitsBuffer, 4, 1); /*'0001'*/
bits_write(&bitsBuffer, 3, ((dts) >> 30) & 0x07); /*DTS[32..30]*/
bits_write(&bitsBuffer, 1, 1);
bits_write(&bitsBuffer, 15, ((dts) >> 15) & 0x7FFF); /*DTS[29..15]*/
bits_write(&bitsBuffer, 1, 1);
bits_write(&bitsBuffer, 15, (dts) & 0x7FFF); /*DTS[14..0]*/
bits_write(&bitsBuffer, 1, 1);
#endif
return 0;
}
int rtpSend::sendRtpPacket(int nChn, char *databuff, int nDataLen, int mark_flag, Data_Info_s* pPacker)
{
// TRACE("sendRtpPacket %d\n", pPacker->u32Ssrc);
int nRet = 0;
int nPlayLoadLen = 0;
int nSendSize = 0;
char szRtpHdr[RTP_HDR_LEN];
memset(szRtpHdr, 0, RTP_HDR_LEN);
//fwrite(databuff, 1, nDataLen, fp);
if (nDataLen + RTP_HDR_LEN <= RTP_MAX_PACKET_BUFF)
{
// 一帧数据发送完后,给mark标志位置1
// makeRtpHeader(szRtpHdr, ((mark_flag == 1) ? 1 : 0), ++pPacker->u16CSeq, (pPacker->sCurPts / 300), pPacker->u32Ssrc);
makeRtpHeader(szRtpHdr, ((mark_flag == 1) ? 1 : 0), ++pPacker->u16CSeq, (pPacker->sCurPts ), pPacker->u32Ssrc);
memcpy(pPacker->szBuff, szRtpHdr, RTP_HDR_LEN);
memcpy(pPacker->szBuff + RTP_HDR_LEN, databuff, nDataLen);
nRet = sendDataByUDP(nChn, pPacker->szBuff, RTP_HDR_LEN + nDataLen);
if (nRet != (RTP_HDR_LEN + nDataLen))
{
TRACE(" udp send error !\n");
return -1;
}
}
else
{
nPlayLoadLen = RTP_MAX_PACKET_BUFF - RTP_HDR_LEN; // 每次只能发送的数据长度 除去rtp头
// makeRtpHeader(pPacker->szBuff, 0, ++pPacker->u16CSeq, (pPacker->sCurPts / 100), pPacker->u32Ssrc);
makeRtpHeader(pPacker->szBuff, 0, ++pPacker->u16CSeq, (pPacker->sCurPts ), pPacker->u32Ssrc);
memcpy(pPacker->szBuff + RTP_HDR_LEN, databuff, nPlayLoadLen);
nRet = sendDataByUDP(nChn, pPacker->szBuff, RTP_HDR_LEN + nPlayLoadLen);
if (nRet != (RTP_HDR_LEN + nPlayLoadLen))
{
TRACE(" udp send error !\n");
return -1;
}
nDataLen -= nPlayLoadLen;
// databuff += (nPlayLoadLen - RTP_HDR_LEN);
databuff += nPlayLoadLen; // 表明前面到数据已经发送出去
databuff -= RTP_HDR_LEN; // 用来存放rtp头
while (nDataLen > 0)
{
if (nDataLen <= nPlayLoadLen)
{
//一帧数据发送完,置mark标志位
// makeRtpHeader(databuff, mark_flag, ++pPacker->u16CSeq, (pPacker->sCurPts / 100), pPacker->u32Ssrc);
makeRtpHeader(databuff, mark_flag, ++pPacker->u16CSeq, (pPacker->sCurPts), pPacker->u32Ssrc);
nSendSize = nDataLen;
}
else
{
// makeRtpHeader(databuff, 0, ++pPacker->u16CSeq, (pPacker->sCurPts / 100), pPacker->u32Ssrc);
makeRtpHeader(databuff, 0, ++pPacker->u16CSeq, (pPacker->sCurPts ), pPacker->u32Ssrc);
nSendSize = nPlayLoadLen;
}
nRet = sendDataByUDP(nChn, databuff, RTP_HDR_LEN + nSendSize);
if (nRet != (RTP_HDR_LEN + nSendSize))
{
TRACE(" udp send error !\n");
return -1;
}
nDataLen -= nSendSize;
databuff += nSendSize;
}
}
return 0;
}
void rtpSend::SaveSpsPps(int nChn, char* pBuf, int nLen, int type)
{
if (nLen < 1024)
{
if (type == 7)
{
memcpy(m_pSps[nChn], pBuf, nLen);
m_nSps[nChn] = nLen;
}
else if (type == 8)
{
memcpy(m_pPps[nChn], pBuf, nLen);
m_nPps[nChn] = nLen;
}
}
return ;
}
void rtpSend::SetSSRC(int nChn, int nSsc)
{
m_DataInfo[nChn].u32Ssrc = nSsc;
}
void rtpSend::SetRemoteAddr(int nChn, char *ip, int nPort)
{
strcpy(m_DataInfo[nChn].dstIP, ip);
m_DataInfo[nChn].nPort = nPort;
}
//获得一个空闲状态的通道
int rtpSend::GetOneIdleChan()
{
for(int i=0; i<MAX_RTP_CHANNEL;i++)
{
if(m_bOpenStream[i] == false)
return i;
}
return -1;
}
#if 0
//SPS(frameType=7)、PPS(frameType=8)和I帧(frameType=5)分开发
int rtpSend::SendH264Stream(int nChn, char *pData, int nFrameLen, uint32_t sCurPts, int frameType)
{
char szPsHead[256];
int nSizePos = 0;
int nSize = 0;
if (frameType == 5)
{
m_bWaitIFrame[nChn] = false;
}
if (frameType != 1 && frameType != 5)
{
SaveSpsPps(nChn, pData, nFrameLen, frameType);
return 0;
}
if (!m_bOpenStream[nChn])
{
return 0;
}
if (m_bWaitIFrame[nChn])
{
return 0;
}
if (m_nPps[nChn] == 0 || m_nSps[nChn] == 0)
return 0;
memset(szPsHead, 0, 256);
m_DataInfo[nChn].sCurPts += 3600;
makePsHeader(szPsHead + nSizePos, m_DataInfo[nChn].sCurPts );
nSizePos += PS_HDR_LEN;
char* pPayload = m_pResBuf[nChn] + 4096;
m_DataInfo[nChn].IFrame = 0;
memcpy(pPayload, pData, nFrameLen);
if (frameType == 5) //I Frame
{
memcpy(pPayload - m_nPps[nChn], m_pPps[nChn], m_nPps[nChn]);
memcpy(pPayload - m_nPps[nChn] - m_nSps[nChn], m_pSps[nChn], m_nSps[nChn]);
pPayload-= m_nPps[nChn];
pPayload-= m_nSps[nChn];
nFrameLen += m_nPps[nChn];
nFrameLen += m_nSps[nChn];
makeSysHeader(szPsHead + nSizePos);
nSizePos += SYS_HDR_LEN;
makePsmHeader(szPsHead + nSizePos);
nSizePos += PSM_HDR_LEN;
m_DataInfo[nChn].IFrame = 1;
}
//加上rtp发送出去,这样的话,后面的数据就只要分片分包就只有加上pes头和rtp头了
if (sendRtpPacket(nChn, szPsHead, nSizePos, 0, &m_DataInfo[nChn]) != 0)
{
return -1;
}
char* pTmp = pPayload - PES_HDR_LEN;
while (nFrameLen > 0)
{
//每次帧的长度不要超过short类型,过了就得分片进循环行发送
nSize = (nFrameLen > PS_PES_PAYLOAD_SIZE) ? PS_PES_PAYLOAD_SIZE : nFrameLen;
// 添加pes头
makePesHeader(pTmp, 0xE0, nSize, (m_DataInfo[nChn].sCurPts / 100), (m_DataInfo[nChn].sCurPts / 300));
// 最后在添加rtp头并发送数据
if (sendRtpPacket(nChn, pTmp, nSize + PES_HDR_LEN, ((nSize == nFrameLen) ? 1 : 0), &m_DataInfo[nChn]) != 0)
{
TRACE("gb28181_send_pack failed!\n");
return -1;
}
nFrameLen -= nSize;
pTmp += nSize;
}
return 0;
}
#else
//SPS(frameType=7)、PPS(frameType=8)和I帧(frameType=5)合在一个帧发
int rtpSend::SendH264Stream(int nChn, char *pData, int nFrameLen, uint32_t sCurPts, int frameType)
{
char szPsHead[256];
int nSizePos = 0;
int nSize = 0;
if (frameType == 7 || frameType == 5) //SPS或I帧
{
m_bWaitIFrame[nChn] = false;
}
if (!m_bOpenStream[nChn] || !m_bCanWrite[nChn])
{
return -2;
}
if (m_bWaitIFrame[nChn])
{
return -3;
}
memset(szPsHead, 0, 256);
//m_DataInfo[nChn].sCurPts += 3600;
m_DataInfo[nChn].sCurPts = sCurPts;
//添加PS头
makePsHeader(szPsHead + nSizePos, m_DataInfo[nChn].sCurPts );
nSizePos += PS_HDR_LEN;
char* pPayload = m_pResBuf[nChn] + 4096;
m_DataInfo[nChn].IFrame = 0;
assert(nFrameLen + 4096 < MAX_RES_BUF); //检查数据是否超过缓冲区大小
memcpy(pPayload, pData, nFrameLen);
if (frameType == 7 || frameType == 5) // I帧需要添加system头和psm头
{
makeSysHeader(szPsHead + nSizePos);
nSizePos += SYS_HDR_LEN;
makePsmHeader(szPsHead + nSizePos);
nSizePos += PSM_HDR_LEN;
m_DataInfo[nChn].IFrame = 1;
}
nSize = (nFrameLen > PS_PES_PAYLOAD_SIZE) ? PS_PES_PAYLOAD_SIZE : nFrameLen;
makePesHeader(szPsHead + nSizePos, 0xE0, nSize, (m_DataInfo[nChn].sCurPts / 100), (m_DataInfo[nChn].sCurPts / 300));
nSizePos += PES_HDR_LEN;
//加上rtp发送出去,这样的话,后面的数据就只要分片分包就只有加上pes头和rtp头了
if (sendRtpPacket(nChn, szPsHead, nSizePos, 0, &m_DataInfo[nChn]) != 0)
{
return -1;
}
//char* pTmp = pPayload - PES_HDR_LEN;
char* pTmp = pPayload;
while (nFrameLen > 0)
{
//每次帧的长度不要超过short类型,过了就得分片进循环行发送
nSize = (nFrameLen > PS_PES_PAYLOAD_SIZE) ? PS_PES_PAYLOAD_SIZE : nFrameLen;
// 添加pes头
//makePesHeader(pTmp, 0xE0, nSize, (m_DataInfo[nChn].sCurPts / 100), (m_DataInfo[nChn].sCurPts / 300));
// 最后在添加rtp头并发送数据
//if (sendRtpPacket(nChn, pTmp, nSize + PES_HDR_LEN, ((nSize == nFrameLen) ? 1 : 0), &m_DataInfo[nChn]) != 0)
if (sendRtpPacket(nChn, pTmp, nSize, ((nSize == nFrameLen) ? 1 : 0), &m_DataInfo[nChn]) != 0)
{
TRACE("sendRtpPacket failed!\n");
return -1;
}
nFrameLen -= nSize;
pTmp += nSize;
}
return 0;
}
int rtpSend::SendAudioStream(int nChn, char *pData, int nFrameLen, uint32_t sCurPts, int frameType)
{
char szPsHead[256];
int nSizePos = 0;
int nSize = 0;
if (frameType == 7 || frameType == 5) //SPS或I帧
{
m_bWaitIFrame[nChn] = false;
}
if (!m_bOpenStream[nChn] || !m_bCanWrite[nChn])
{
return -2;
}
if (m_bWaitIFrame[nChn])
{
return -3;
}
memset(szPsHead, 0, 256);
//m_DataInfo[nChn].sCurPts += 3600;
m_DataInfo[nChn].sCurPts = sCurPts;
//添加PS头
makePsHeader(szPsHead + nSizePos, m_DataInfo[nChn].sCurPts );
nSizePos += PS_HDR_LEN;
char* pPayload = m_pResBuf[nChn] + 4096;
m_DataInfo[nChn].IFrame = 0;
assert(nFrameLen + 4096 < MAX_RES_BUF); //检查数据是否超过缓冲区大小
memcpy(pPayload, pData, nFrameLen);
if (frameType == 7 || frameType == 5) // I帧需要添加system头和psm头
{
makeSysHeader(szPsHead + nSizePos);
nSizePos += SYS_HDR_LEN;
makePsmHeader(szPsHead + nSizePos);
nSizePos += PSM_HDR_LEN;
m_DataInfo[nChn].IFrame = 1;
}
nSize = (nFrameLen > PS_PES_PAYLOAD_SIZE) ? PS_PES_PAYLOAD_SIZE : nFrameLen;
makePesHeader(szPsHead + nSizePos, 0xC0, nSize, (m_DataInfo[nChn].sCurPts / 100), (m_DataInfo[nChn].sCurPts / 300));
nSizePos += PES_HDR_LEN;
//加上rtp发送出去,这样的话,后面的数据就只要分片分包就只有加上pes头和rtp头了
//fwrite(szPsHead, 1, nSizePos, fp);
if (sendRtpPacket(nChn, szPsHead, nSizePos, 0, &m_DataInfo[nChn]) != 0)
{
return -1;
}
//char* pTmp = pPayload - PES_HDR_LEN;
char* pTmp = pPayload;
while (nFrameLen > 0)
{
//每次帧的长度不要超过short类型,过了就得分片进循环行发送
nSize = (nFrameLen > PS_PES_PAYLOAD_SIZE) ? PS_PES_PAYLOAD_SIZE : nFrameLen;
// 添加pes头
//makePesHeader(pTmp, 0xE0, nSize, (m_DataInfo[nChn].sCurPts / 100), (m_DataInfo[nChn].sCurPts / 300));
// 最后在添加rtp头并发送数据
//if (sendRtpPacket(nChn, pTmp, nSize + PES_HDR_LEN, ((nSize == nFrameLen) ? 1 : 0), &m_DataInfo[nChn]) != 0)
//fwrite(pTmp, 1, nSize, fp);
if (sendRtpPacket(nChn, pTmp, nSize, ((nSize == nFrameLen) ? 1 : 0), &m_DataInfo[nChn]) != 0)
{
TRACE("sendRtpPacket failed!\n");
return -1;
}
nFrameLen -= nSize;
pTmp += nSize;
}
return 0;
}
#endif
int rtpSend::SendPSStream(int nChn, char *pData, int nFrameLen, uint32_t sCurPts, int mark_flag)
{
//ATLASSERT(nFrameLen < 65535);
if (!m_bOpenStream[nChn] || !m_bCanWrite[nChn])
{
return -2;
}
m_DataInfo[nChn].sCurPts = sCurPts;
// 最后在添加rtp头并发送数据
if (sendRtpPacket(nChn, pData, nFrameLen, mark_flag, &m_DataInfo[nChn]) != 0)
{
TRACE("sendRtpPacket failed!\n");
return -1;
}
return 0;
}
调用部分程序
基于gitee的李通发布的程序作为基础上进行修改
gitee链接:https://gitee.com/zhfqx/c-sip-gb28181-client
gb28181Management.h
#ifndef __GB28181_MANAGEMENT_H__
#define __GB28181_MANAGEMENT_H__
#include <stdio.h>
#include "gb28181Client.h"
#include "rtpsend.h" //RTP 封包并发送
#pragma pack(1) //强制1字节对齐
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 short seq_no;
/* bytes 4-7 */
unsigned int timestamp;
/* bytes 8-11 */
unsigned int ssrc; /* stream number is used here. */
}RTP_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;
#pragma pack(pop)
/*
+---------------+
|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
typedef struct _media_para{
char control_type[20];
char media_ip[30];
char media_port[10];
char ipc_media_port[20];
}MEDIA_PARA;
//GB28181客户端
class Gb28181Management:public LSMXGb28181Client
{
public :
static Gb28181Management *createNew(DEVICE_INFO device_info,DEVICE_STATUS device_status);
~Gb28181Management();
int setGB28181Para(DEVICE_INFO device_info,
DEVICE_STATUS device_statu);
NALU_t *AllocNALU(int buffersize);
int test(DEVICE_INFO device_info,DEVICE_STATUS device_status);
void FreeNALU(NALU_t *n); //释放nal 资源
int OpenBitstreamFile (char *fn);//打开本地要传输的文件
int FindStartCode2 (unsigned char *Buf);
int FindStartCode3 (unsigned char *Buf);
int GetAnnexbNALU (NALU_t *nalu); //获取一nal数据
protected :
Gb28181Management(DEVICE_INFO device_info,DEVICE_STATUS device_status);
private :
/*媒体控制:实时点播/回放/下载 */
/*control_type:媒体控制类型,实时点播/Play,回放/Playback,下载/Download*/
/*media_ip:媒体服务器IP地址*/
/*media_port:媒体服务器IP端口*/
/*返回值:成功时返回0,失败时返回负值*/
int dt_eXosip_mediaControl(char *control_type, char *media_ip, char *media_port, char *ipc_media_port);
/*发送视频流*/
static void *SendRtpProc(void *arg);
MEDIA_PARA pMedia_para;
rtpSend *m_pRtpSend ;
int mRtpChnId;
FILE * pinfile = NULL; //测试使用打开文件的描述符
};
#endif
gb28181Management.cpp
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <iostream>
#include <string>
#include <unistd.h>
#include <pthread.h>
#include "gb28181Management.h"
#ifdef __unix
#define fopen_s(pFile,filename,mode) ((*(pFile))=fopen((filename), (mode)))==NULL
#endif
#define dbg(a,...) printf(" DEBUG :%s(%d)-<%s>: %s\r\n",__FILE__, __LINE__, __FUNCTION__,a)
Gb28181Management*
Gb28181Management::createNew(DEVICE_INFO device_info,
DEVICE_STATUS device_statu){
Gb28181Management* gb28181Management = new Gb28181Management(device_info,
device_statu);
dbg("Gb28181ManagementGb28181ManagementGb28181ManagementGb28181Management");
if(gb28181Management == NULL)
{
return NULL;
}
if (gb28181Management->init() == false){
delete gb28181Management;
dbg("Gb28181Management->init() NONO!!");
return NULL;
}
if (gb28181Management->startUp() == false){
delete gb28181Management;
dbg("Gb28181Management->start() NONO!!");
return NULL;
}
return gb28181Management;
}
Gb28181Management::~Gb28181Management(){
}
int
Gb28181Management::setGB28181Para(DEVICE_INFO device_info,
DEVICE_STATUS device_statu){
if (setPara(device_info,device_statu) == false){
dbg("Gb28181Management->setPara()");
return -1;
}
//if (init() == false){
// dbg("Gb28181Management->init()");
// return -1;
//}
if (startUp() == false){
dbg("Gb28181Management->startUp()");
return -1;
}
return 0;
}
NALU_t *
Gb28181Management::AllocNALU(int buffersize)
{
NALU_t *n;
if ((n = (NALU_t*)calloc (1, sizeof(NALU_t))) == NULL)
{
dbg("AllocNALU Error: Allocate Meory To NALU_t Failed ");
exit(0);
}
n->max_size=buffersize; //Assign buffer size
if ((n->buf = (unsigned char*)calloc (buffersize, sizeof (char))) == NULL)
{
free (n);
dbg ("AllocNALU Error: Allocate Meory To NALU_t Buffer Failed ");
exit(0);
}
return n;
}
int Gb28181Management::test(DEVICE_INFO device_info,DEVICE_STATUS device_status){
dbg("test == \r\n");
getLinkStatus();
}
void
Gb28181Management::FreeNALU(NALU_t *n)
{
if (n)
{
if (n->buf)
{
free(n->buf);
n->buf=NULL;
}
free (n);
}
}
int
Gb28181Management::OpenBitstreamFile (char *fn)
{
printf("fn == %s\r\n",fn);
if (0 != fopen_s(&pinfile,fn,"rb"))
{
dbg("Error: Open input file error\n");
getchar();
}
return 1;
}
int
Gb28181Management::FindStartCode2 (unsigned char *Buf)
{
if(Buf[0]!=0 || Buf[1]!=0 || Buf[2] !=1 || (Buf[3] !=0xba && Buf[3]!=0xc0) ) //Check whether buf is 0x000001
{
return 0;
}
else
{
return 1;
}
}
int
Gb28181Management::FindStartCode3 (unsigned char *Buf)
{
if(Buf[0]!=0 || Buf[1]!=0 || Buf[2] !=0 || Buf[3] !=1 || (Buf[4] !=0xba && Buf[4]!=0xc0)) //Check whether buf is 0x00000001
{
return 0;
}
else
{
return 1;
}
}
int
Gb28181Management::GetAnnexbNALU (NALU_t *nalu)
{
int pos = 0; //一个nal到下一个nal 数据移动的指针
int StartCodeFound = 0; //是否找到下一个nal 的前缀
int rewind = 0; //判断 前缀所占字节数 3或 4
unsigned char * Buf = NULL;
static int info2 =0 ;
static int info3 =0 ;
if ((Buf = (unsigned char*)calloc (nalu->max_size , sizeof(char))) == NULL)
{
dbg ("GetAnnexbNALU Error: Could not allocate Buf memory\n");
}
nalu->startcodeprefix_len = 4; //初始化前缀位三个字节
if (4 != fread (Buf, 1, 4, pinfile))//从文件读取三个字节到buf
{
free(Buf);
return 0;
}
info2 = FindStartCode2 (Buf); //Check whether Buf is 0x000001ba or 0x000001c0
if(info2 != 1)
{
//If Buf is not 0x000001,then read one more byte
if(1 != fread(Buf+4, 1, 1, pinfile))
{
free(Buf);
return 0;
}
info3 = FindStartCode3 (Buf); //Check whether Buf is 0x00000001
if (info3 != 1) //If not the return -1
{
free(Buf);
system("pause");return -1;
}
else
{
//If Buf is 0x00000001,set the prefix length to 5 bytes
pos = 5;
nalu->startcodeprefix_len = 5;
}
}
else
{
//If Buf is 0x000001,set the prefix length to 3 bytes
pos = 4;
nalu->startcodeprefix_len = 4;
}
//寻找下一个字符符号位, 即 寻找一个nal 从一个0000001 到下一个00000001
StartCodeFound = 0;
info2 = 0;
info3 = 0;
while (!StartCodeFound)
{
if (feof (pinfile)) //如果到了文件结尾
{
//nalu->len = (pos-1) - nalu->startcodeprefix_len; //从0 开始
nalu->len = pos - 1;
//memcpy (nalu->buf, &Buf[nalu->startcodeprefix_len], nalu->len);
memcpy(nalu->buf,Buf,nalu->len);
nalu->forbidden_bit = nalu->buf[nalu->startcodeprefix_len] & 0x80; // 1 bit--10000000
nalu->nal_reference_idc = nalu->buf[nalu->startcodeprefix_len] & 0x60; // 2 bit--01100000
nalu->nal_unit_type = (nalu->buf[nalu->startcodeprefix_len]) & 0x1f; // 5 bit--00011111
free(Buf);
return pos-1;
}
Buf[pos++] = fgetc (pinfile); //Read one char to the Buffer 一个字节一个字节从文件向后找
info3 = FindStartCode3(&Buf[pos-5]); //Check whether Buf is 0x00000001
if(info3 != 1)
{
info2 = FindStartCode2(&Buf[pos-4]); //Check whether Buf is 0x000001
}
StartCodeFound = (info2 == 1 || info3 == 1); //如果找到下一个前缀
}
rewind = (info3 == 1)? -5 : -4;
if (0 != fseek (pinfile, rewind, SEEK_CUR)) //将文件内部指针移动到 nal 的末尾
{
free(Buf);
dbg("GetAnnexbNALU Error: Cannot fseek in the bit stream file");
}
//nalu->len = (pos + rewind) - nalu->startcodeprefix_len; //设置包含nal 头的数据长度
nalu->len = pos +rewind;
//memcpy (nalu->buf, &Buf[nalu->startcodeprefix_len], nalu->len);//拷贝一个nal 数据到数组中
memcpy(nalu->buf,Buf,nalu->len);
nalu->forbidden_bit = nalu->buf[nalu->startcodeprefix_len] & 0x80; //1 bit 设置nal 头
nalu->nal_reference_idc = nalu->buf[nalu->startcodeprefix_len] & 0x60; // 2 bit
nalu->nal_unit_type = (nalu->buf[nalu->startcodeprefix_len]) & 0x1f; // 5 bit
free(Buf);
return (pos + rewind); //Return the length of bytes from between one NALU and the next NALU
}
Gb28181Management::Gb28181Management(DEVICE_INFO device_info,
DEVICE_STATUS device_status):
LSMXGb28181Client(device_info,device_status)
{
}
int
Gb28181Management::dt_eXosip_mediaControl(char *control_type, char *media_ip, char *media_port, char *ipc_media_port)
{
static bool threadIsExist = false;
pthread_t ntid;
static void * sendHandle = 0;
//dword existCode;
//pMedia_para->control_type = control_type;
//pMedia_para->media_ip = media_ip;
//pMedia_para->media_port = media_port;
//pMedia_para->ipc_media_port = ipc_media_port;
strcpy(pMedia_para.control_type,control_type);
strcpy(pMedia_para.media_ip,media_ip);
strcpy(pMedia_para.media_port,media_port);
strcpy(pMedia_para.ipc_media_port,ipc_media_port);
//创建RPT封包函数以及发送函数
m_pRtpSend = rtpSend::createNew();
unsigned int nSSRC = 999999999;
mRtpChnId = m_pRtpSend->GetOneIdleChan();
m_pRtpSend->SetRemoteAddr(mRtpChnId, pMedia_para.media_ip, atoi(pMedia_para.media_port));
m_pRtpSend->SetSSRC(mRtpChnId, nSSRC);
m_pRtpSend->OpenStream(mRtpChnId);
m_pRtpSend->SetWritable(mRtpChnId, true); //打开发送开关
if(threadIsExist)
{
threadIsExist = false;
//GetExitCodeProcess(sendHandle,&existCode); //获取一个已经终端的进程代码
//if(TerminateThread(sendHandle,existCode)) //退出线程
if(1)
{
sendHandle = 0;
//sendHandle = CreateThread(NULL,0,SendRtpProc,(LPVOID)&media_para,0,NULL);
}else
{
dbg("terminateThread failed! error code is ;%s\n","GetLastError()");
}
}else{
int err=pthread_create(&ntid,NULL,SendRtpProc,this); //创建一个线程
if(err!=0)
{
dbg("create thread failed:pthreadSendRtpProc\n");
return -1;
}
//sendHandle = CreateThread(NULL,0,SendRtpProc,(LPVOID)&media_para,0,NULL);
}
if(sendHandle > 0)
threadIsExist = true;
return 0;
}
void *
Gb28181Management::SendRtpProc(void *arg){
#if 1
Gb28181Management *mGb28181Management = (Gb28181Management*)arg;
NALU_t * n = NULL;
int timestamp = 0; //时间戳
int marker = 0; // 标志位,具体作用未知
mGb28181Management->OpenBitstreamFile("/root/gb28181/a.ps"); //打开本地要传输的文件
n = mGb28181Management->AllocNALU(8000000); //分配nal 资源
while(!feof(mGb28181Management->pinfile) && mGb28181Management->getRealPlay()>0){ //如果未到文件结尾
//while(1){
for(int i = 0;i<20;i++)
usleep(9000);
Gb28181Management *mGb28181Management = (Gb28181Management*)arg;
int socket_cli;
struct sockaddr_in addrser;//Initialize Win Socket
sockaddr_in addrMe; //源端口和地址
NALU_t * n = NULL;
char sendbuf[MAXDATASIZE];
RTP_HEADER * rtp_hdr = NULL ;
int pocket_number = 0; //包号
int frame_number = 0; //帧号
int total_sent = 0; //已经发送的总共数据
NALU_HEADER * nalu_hdr = NULL;
char* nalu_payload = NULL;
int bytes = 0; //一次发送的数据
//unsigned int sequence = 65536;
int timestamp = 0;
FU_INDICATOR *fu_ind = NULL ;
FU_HEADER *fu_hdr = NULL ;
//创建socket套接字
addrMe.sin_family = AF_INET;
addrMe.sin_port = htons(atoi(mGb28181Management->pMedia_para.ipc_media_port));//1001你的端口号
addrMe.sin_addr.s_addr = INADDR_ANY;
socket_cli= socket(AF_INET ,SOCK_DGRAM/*UDP协议的是流式*/,0);
addrser.sin_addr.s_addr =inet_addr(mGb28181Management->pMedia_para.media_ip);
addrser.sin_family = AF_INET;
addrser.sin_port = htons(atoi(mGb28181Management->pMedia_para.media_port)); //网络字节序
bind(socket_cli, (struct sockaddr*)&addrMe, sizeof(addrMe));
mGb28181Management->OpenBitstreamFile(".\\3.ps"); //打开本地要传输的文件
n = mGb28181Management->AllocNALU(8000000); //分配nal 资源
mGb28181Management->FreeNALU(n); //释放nal 资源
//fclose(pinfile);
//closesocket(socket_cli); //关闭套接字
//WSACleanup();
#endif
return NULL;
}
主程序调用部分
main.cpp
#include <stdio.h>
#include <unistd.h>
#include "gb28181Management.h"
#define dbg(a,...) printf(" DEBUG :%s(%d)-<%s>: %s\r\n",__FILE__, __LINE__, __FUNCTION__,a)
#if 1
//主函数
int main (int argc, char *argv[])
{
DEVICE_INFO device_info;
DEVICE_STATUS device_status;
DT_EXOSIP_CALLBACK dt_eXosip_callback;
char eXosip_server_id[30] = "34020000002000000002"; //服务器ID
char eXosip_server_ip[20] = "192.168.6.30"; //服务器IP地址
char eXosip_server_port[10] = "15060"; //服务器端口
//char eXosip_ipc_id[30] = "001200000410000";
char eXosip_ipc_id[30] = "34020000001320000007"; //设备ID
char eXosip_ipc_pwd[20] = "admin"; //设备验证密码
char eXosip_ipc_ip[20] = "192.168.6.46"; //设备IP
char eXosip_ipc_media_port[10] = "20043"; //设备流端口
char eXosip_ipc_sess_port[10] = "25183"; //设备协议端口
//char eXosip_alarm_id[30] = "001200000410010"; //"34020000001340000005";
char eXosip_alarm_id[30] = "34020000001340000010"; //设备报警通道编号
char eXosip_media_ip[30] = "10.0.0.99"; //设备报警通道编号
char eXosip_media_port[10] = "6000"; //设备报警通道编号
char eXosip_device_name[30] = "LS-33"; //设备通道名称
char eXosip_device_manufacturer[30] = "LS"; //设备通道厂家
char eXosip_device_model[30] = "ABC_model2"; //设备通道厂家
char eXosip_device_firmware[30] = "V1.0";
char eXosip_device_encode[10] = "ON";
char eXosip_device_record[10] = "OFF";
char eXosip_status_on[10] = "ON";
char eXosip_status_ok[10] = "OK";
char eXosip_status_online[10] = "ONLINE";
char eXosip_status_guard[10] = "OFFDUTY";
char eXosip_status_time[30] = "2014-01-17T16:30:20";
device_info.server_id = eXosip_server_id;
device_info.server_ip = eXosip_server_ip;
device_info.server_port = eXosip_server_port;
device_info.ipc_id = eXosip_ipc_id;
device_info.ipc_pwd = eXosip_ipc_pwd;
device_info.ipc_ip = eXosip_ipc_ip;
device_info.ipc_media_port = eXosip_ipc_media_port;
device_info.ipc_sess_port = eXosip_ipc_sess_port;
device_info.alarm_id =eXosip_alarm_id;
device_info.media_ip =eXosip_media_ip;
device_info.media_port =eXosip_media_port;
device_info.device_name = eXosip_device_name;
device_info.device_manufacturer = eXosip_device_manufacturer;
device_info.device_model = eXosip_device_model;
device_info.device_firmware = eXosip_device_firmware;
device_info.device_encode = eXosip_device_encode;
device_info.device_record = eXosip_device_record;
device_status.status_on = eXosip_status_on;
device_status.status_ok = eXosip_status_ok;
device_status.status_online = eXosip_status_online;
device_status.status_guard = eXosip_status_guard;
device_status.status_time = eXosip_status_time;
//回调函数之后再写
#if 0
dt_eXosip_callback.dt_eXosip_deviceControl = dt_eXosip_deviceControl;
dt_eXosip_callback.dt_eXosip_getDeviceInfo = dt_eXosip_getDeviceInfo;
dt_eXosip_callback.dt_eXosip_getDeviceStatus = dt_eXosip_getDeviceStatus;
dt_eXosip_callback.dt_eXosip_getRecordTime = dt_eXosip_getRecordTime;
dt_eXosip_callback.dt_eXosip_mediaControl = dt_eXosip_mediaControl;
dt_eXosip_callback.dt_eXosip_playControl = dt_eXosip_playControl;
#else
#endif
Gb28181Management *gb28181Management = Gb28181Management::createNew(device_info,device_status);
if (gb28181Management == NULL) {
dbg("gb28181Client ==NULL");
}else{
dbg("gb28181Client YES!!");
}
sleep(2);
device_info.ipc_id = "34020000001320000009";
device_info.server_ip = "192.168.6.21";
dbg("main setPara!!");
gb28181Management->setGB28181Para(device_info, device_status);
dbg("main Lop!!");
while(1);
dbg("main end!!");
return (0);
}
#endif