2014년 12월 4일 목요일

H.264 RFC3984 NAL 패킷전송

 typedef unsigned short   WORD;  
 typedef unsigned long    DWORD;  
   
 typedef unsigned char          uint8_t;  
 typedef unsigned short          uint16_t;  
 typedef unsigned int          uint32_t;  
 typedef unsigned __int64     uint64_t;  
   
 typedef unsigned char          u_int8_t;  
 typedef unsigned short          u_int16_t;  
 typedef unsigned int          u_int32_t;  
 typedef unsigned __int64     u_int64_t;  
   
 typedef struct   
 {                      
      WORD  cc:   4;   /* csrc count */  
      WORD  ext:  1;   /* header extension flag */  
      WORD  pad:  1;   /* padding flag - for encryption */  
      WORD  ver:  2;   /* protocal version */  
      WORD  pt:   7;   /* payload type */  
      WORD  mk:   1;   /* marker bit - for profile */  
      WORD     seq;               /* sequence number of this packet */  
      DWORD     ts;                    /* timestamp of this packet */  
      DWORD     ssrc;               /* source of packet */  
 } RTP_HEADER;  
   
 #define RTP_SEND_SIZE     (1440)  
   
 int trimStartCode(uint8_t *buf, int len)  
 {  
      uint8_t *ptr = buf;  
      if (len < 4) return 0;  
   
      // trying to find 0x00 0x00 ... 0x01 pattern  
      // find first 0x00 0x00 bytes  
      if (ptr[0] == 0x00 && ptr[1] == 0x00) {  
           // find first 0x01  
           while (*ptr == 0x00 && ptr < buf+len-1)  
                ptr++;  
   
           if (*ptr != 0x01) {     // error - invalid stream  
                DPRINTF("invalid stream, 0x%02x\n", *ptr);  
                ptr = buf;  
           } else {  
                ptr++;  
           }  
      }  
   
      return ptr-buf;  
 }  
   
 void RTPSender::resetRtpHeader(uint8_t payload, uint8_t marker, uint32_t timestamp)  
 {  
      RTP_HEADER *pRtpHeader = (RTP_HEADER *)m_pRtpSendBuffer;  
      memset(pRtpHeader, 0, sizeof(RTP_HEADER));  
   
      pRtpHeader->ver = 2;  
      pRtpHeader->pt = payload;  
      pRtpHeader->mk = marker;  
      pRtpHeader->ts = htonl(timestamp);  
   
      uint16_t seqNum = 0;  
      seqNum = m_nSequenceNum++;  
      if (m_nSequenceNum >= 0xffff)  
           m_nSequenceNum = 0;  
      pRtpHeader->seq = htons(seqNum);  
 }  
   
 uint32_t RTPSender::convertToRTPTimestamp(unsigned int frequency, __int64 timestamp)  
 {  
      __int64 rtp_timestamp = (__int64)frequency * timestamp / (__int64)1000;  
      return rtp_timestamp;  
 }  
   
 int H264Sender::sendRtpData(MediaBuffer *pBuffer)  
 {       
      RTP_HEADER *pRtpHeader = (RTP_HEADER *)m_pRtpSendBuffer;  
      int offset = trimStartCode(pBuffer->data, pBuffer->size);  
      int bytesToSend = pBuffer->size-offset;  
      uint8_t *pSrc = &pBuffer->data[offset];  
      uint8_t *pDest = (uint8_t *)m_pRtpSendBuffer;  
      int rtphdr_size = sizeof(RTP_HEADER);  
      int pktcount = 0;    
   
      const char *track = "track1";  
      uint32_t timestamp = convertToRTPTimestamp(m_nTimestampFrequency, pBuffer->dts);  
   
      int sendToLen;  
   
      while (bytesToSend > RTP_SEND_SIZE)  
      {  
           resetRtpHeader(m_nPayloadType, 0, timestamp);  
           pDest = (uint8_t *)&m_pRtpSendBuffer[rtphdr_size];  
   
           pDest[0] = (pSrc[0] & 0xE0) | 28;  
           if (pktcount == 0) {  
                memcpy(&pDest[1], pSrc, RTP_SEND_SIZE);  
                pDest[1] = 0x80 | (pSrc[0] & 0x1F);
                sendToLen = RTP_SEND_SIZE + rtphdr_size + 1;  
           } else {  
                pDest[1] = pSrc[0] & 0x1F;
                memcpy(&pDest[2], pSrc, RTP_SEND_SIZE);  
                sendToLen = RTP_SEND_SIZE + rtphdr_size + 2;  
           }  
           pSrc += RTP_SEND_SIZE;  
   
           m_pServerSession->sendClientRtp(track, m_pRtpSendBuffer, sendToLen);  
                  
           bytesToSend -= RTP_SEND_SIZE;  
           pktcount++;  
      }  
   
      if (bytesToSend > 0) {  
           resetRtpHeader(m_nPayloadType, 1, timestamp);  
           pDest = (uint8_t *)&m_pRtpSendBuffer[rtphdr_size];  
   
           if (pktcount == 0) {  
                memcpy(pDest, pSrc, bytesToSend);  
                sendToLen = bytesToSend + rtphdr_size;  
           } else {     // FU-A last packet  
                pDest[0] = 0x20 | 28;  
                pDest[1] = 0x40;  
                memcpy(&pDest[2], pSrc, bytesToSend);  
                sendToLen = bytesToSend + rtphdr_size + 2;  
           }            
   
           m_pServerSession->sendClientRtp(track, m_pRtpSendBuffer, sendToLen);  
      }  
   
      return 0;  
 }