GB28181 设备端移植 : 下端发送视频程序编写

上一节编写了注册流程以及交互部分程序,这一节来进行程序调用以及发送视频流部分的程序编写

发送视频流部分程序

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
您好,我可以为您提供一些将OpenCV移植Linux系统并编写人脸识别程序的步骤: 1. 下载并安装OpenCV:您可以从OpenCV的官方网站下载源代码,并按照它们提供的指南进行编译和安装。请注意,这可能需要一些时间和技能。 2. 连接CIS相机:将CIS相机连接到Linux系统并确保它能够被系统识别。可以使用以下命令查看系统是否能够识别相机: ``` lsusb ``` 如果相机被识别,您将看到一个类似于以下内容的输出: ``` Bus 001 Device 003: ID 12d1:1001 Huawei Technologies Co., Ltd. E169/E620/E800 HSDPA Modem Bus 001 Device 005: ID 0c45:63e0 Microdia Sonix Integrated Webcam ``` 其中,ID是相机的厂商ID和产品ID。 3. 编写人脸识别程序:使用OpenCV的人脸识别功能编写程序。以下是一个简单的Python示例程序,用于从相机捕获视频并检测人脸: ``` import cv2 face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') cap = cv2.VideoCapture(0) while True: ret, frame = cap.read() gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, 1.3, 5) for (x,y,w,h) in faces: cv2.rectangle(frame, (x,y), (x+w,y+h), (255,0,0), 2) cv2.imshow('frame', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows() ``` 请注意,此示例假定您已经下载并安装了OpenCV,并已下载名为haarcascade_frontalface_default.xml的人脸识别分类器文件。您可以在OpenCV的官方网站上找到这个文件,并将其放在与示例程序相同的目录中。 希望这可以帮助您!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值