레이블이 스트리밍인 게시물을 표시합니다. 모든 게시물 표시
레이블이 스트리밍인 게시물을 표시합니다. 모든 게시물 표시

2015년 10월 7일 수요일

비디오 코덱과 스트리밍 프로토콜

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;  
 }  
   

2013년 12월 26일 목요일

RTP Header Parsing

< RTPHeader.h >

#ifndef __RTP_HEADER_H__
#define __RTP_HEADER_H__

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 int u_int32_t;
typedef unsigned short u_int16_t;
typedef unsigned char u_int8_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;

class RtpHeader {
public:
RtpHeader(uint8_t *buf, int len);
virtual ~RtpHeader();

uint8_t* payload();
int length() { return fLength; }
int payloadLen();

uint16_t version() { return fVersion; }
uint16_t padding() { return fPadding; }
uint16_t extension() { return fExtension; }
uint16_t csrcCount() { return fCSRCCount; }
uint16_t markerBit() { return fMarkerBit; }
uint16_t payloadType() { return fPayloadType; }
uint16_t sequenceNum() { return fSequenceNum; }
uint32_t timestamp() { return fTimestamp; }
uint32_t ssrc() { return fSSRC; }

private:
uint8_t* fBuf;
int fLength;
uint16_t fVersion;
uint16_t fPadding;
uint16_t fExtension;
uint16_t fCSRCCount;
uint16_t fMarkerBit;
uint16_t fPayloadType;
uint16_t fSequenceNum;
uint32_t fTimestamp;
uint32_t fSSRC;

uint8_t *fCurPtr;
};

#endif


< RTPHeader.cpp >

#include <Winsock2.h>
#include "RTPHeader.h"

RtpHeader::RtpHeader(uint8_t *buf, int len) : fBuf(NULL), fLength(0), fVersion(0), fPadding(0), fExtension(0), fCSRCCount(0),
fMarkerBit(0), fPayloadType(0), fSequenceNum(0), fTimestamp(0), fSSRC(0)
{
if (len < sizeof(RTP_HEADER))
return;

fBuf = fCurPtr = buf;
fLength = len;

RTP_HEADER *p = (RTP_HEADER *)buf;
fCSRCCount = p->cc;
fExtension = p->ext;
fPadding = p->pad;
fVersion = p->ver;
fPayloadType = p->pt;
fMarkerBit = p->mk;
fSequenceNum = ntohs(p->seq);
fTimestamp = ntohl(p->ts);
fSSRC = ntohl(p->ssrc);

fCurPtr += sizeof(RTP_HEADER);

// check RTP version (it must be 2)
if (fVersion != 2)
DPRINTF("invalid rtp version %u\n", fVersion);

// skip CSRC
if (fCSRCCount > 0) {
if (payloadLen() <= fCSRCCount*4) {
DPRINTF("invalid rtp header, CSRC count error %u\n", fCSRCCount);
} else {
fCurPtr += (fCSRCCount*4);
}
}

// skip Extension field
if (fExtension) {
if (payloadLen() <= 4) {
DPRINTF("invalid rtp header, extension length error\n");
} else {
unsigned extHdr = ntohl(*(unsigned *)fCurPtr); fCurPtr += 4;
unsigned remExtSize = 4*(extHdr&0xFFFF);
if (payloadLen() <= remExtSize) {
DPRINTF("invalid rtp header, extension size error %u\n", remExtSize);
} else {
fCurPtr += remExtSize;
}
}
}

// remove padding
if (fPadding) {
if (payloadLen() <= 0) {
DPRINTF("invalid rtp header, padding error\n");
} else {
unsigned numPaddingBytes = (unsigned)fBuf[fLength-1];
if (payloadLen() <= numPaddingBytes) {
DPRINTF("invalid rtp header, padding number error\n");
} else {
fLength -= numPaddingBytes;
    fPadding = p->pad = 0;
}
}
}
}

RtpHeader::~RtpHeader()
{
}

uint8_t* RtpHeader::payload()
{
return fCurPtr;
}

int RtpHeader::payloadLen()
{
uint8_t *ptrLast = &fBuf[fLength-1];
return ptrLast-fCurPtr+1;
}


< 사용 >
...
RtpHeader *rtp = new RtpHeader((uint8_t*)buf, len);

unsigned short pt = rtp->payloadType();
unsigned short mk = rtp->markerBit();
unsigned short seqnum = rtp->sequenceNum();
unsigned int ts = rtp->timestamp();
unsigned int rtpSSRC = rtp->ssrc();

 delete rtp;

2012년 6월 8일 금요일

H.264 RFC3984 NAL 패킷처리 - H.264 RFC3984 NAL Packet Handling

 class RTPSource  
 {  
      uint8_t*               fFrameBuf;    // 프레임 버퍼 - 한개 프레임 될때까지 채움
      int                    fFrameBufPos; // 프레임 버퍼 인덱스 - 현재 프레임 버퍼 사이즈 
      FrameHandlerFunc       fFrameHandlerFunc;        // 콜백함수 - 한개 프레임이 완성되면 호출
      void*                  fFrameHandlerFuncData;    // 콜백함수 데이터
      
      uint8_t*               fExtraData;        // SPS/PPS 정보
      unsigned               fExtraDataSize;
      ...  
 }

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 RTPSource::copyToFrameBuffer(uint8_t *buf, int len)  
 {  
      if (fFrameBufPos+len >= FRAME_BUFFER_SIZE) {  
           DPRINTF("RTP Frame Buffer overflow %s\n", fCodecName);  
           fFrameBufPos = 0;  
      }  
      memmove(&fFrameBuf[fFrameBufPos], buf, len);  
      fFrameBufPos += len;  
 }  
   
 void RTPSource::resetFrameBuf()  
 {  
      fFrameBufPos = 0;  
 }  
   
 uint64_t RTPSource::getMediaTimestamp(uint32_t timestamp)  
 {  
      uint64_t msec = 1000;  
      uint64_t time_msec = timestamp*msec/fTimestampFrequency;  
      return time_msec;  
 }  
   
 void H264RTPSource::putStartCode()  
 {  
      fFrameBuf[fFrameBufPos++] = 0x00;  
      fFrameBuf[fFrameBufPos++] = 0x00;  
      fFrameBuf[fFrameBufPos++] = 0x00;  
      fFrameBuf[fFrameBufPos++] = 0x01;  
 }  
   
 void H264RTPSource::processFrame(RTPPacketBuffer *packet)  
 {  
      uint8_t *buf = (uint8_t *)packet->payload();  
      int len = packet->payloadLen();  
   
      int offset = trimStartCode(buf, len);  
      buf = &buf[offset];  
      len -= offset;  
   
      uint8_t *buf_ptr = buf;  
      bool isCompleteFrame = false;  
   
      uint32_t media_timestamp = getMediaTimestamp(packet->timestamp());  
   
      uint8_t nalUnitType = (buf[0]&0x1F);  
   
      if (RTSPCommonEnv::nDebugFlag&DEBUG_FLAG_RTP_PAYLOAD)  
           DPRINTF("nal_type: %d, size: %d\n", nalUnitType, len);  
   
      if (!fIsStartFrame) {  
           if (fExtraData) {  
                putStartCode();  
                copyToFrameBuffer(fExtraData, fExtraDataSize);  
           }  
           fIsStartFrame = true;  
      }  
   
      switch (nalUnitType)  
      {  
      case 28: {     // FU-A  
           uint8_t startBit = buf[1]&0x80;  
           uint8_t endBit = buf[1]&0x40;  
   
           if (startBit) {  
                buf_ptr++; len--;  
                buf[1] = (buf[0]&0xE0) + (buf[1]&0x1F);  
                putStartCode();  
           } else {  
                buf_ptr += 2; len -= 2;  
           }  
   
           copyToFrameBuffer(buf_ptr, len);  
           isCompleteFrame = (endBit != 0);            
           break;  
                 }  
      case 5: {     // IDR-Picture  
           putStartCode();  
           copyToFrameBuffer(buf_ptr, len);  
           isCompleteFrame = true;  
           break;  
                }  
      case 7: {     // SPS  
           putStartCode();  
           copyToFrameBuffer(buf_ptr, len);  
           isCompleteFrame = false;  
           break;  
                }  
      case 8: {     // PPS  
           putStartCode();  
           copyToFrameBuffer(buf_ptr, len);  
           isCompleteFrame = false;  
           break;  
                }  
      case 24: {     // STAP-A  
           buf_ptr++; len--;  
           while (len > 3)  
           {  
                uint16_t staplen = (buf_ptr[0]<<8) | (buf_ptr[1]);  
                if (staplen > len) {  
                     DPRINTF("STAP-A process error, staplen: %d, len\n", staplen, len);  
                     break;  
                }  
   
                buf_ptr += 2; len -= 2;  
                nalUnitType = buf_ptr[0]&0x1F;  
   
                putStartCode();  
                copyToFrameBuffer(buf_ptr, staplen);  
   
                buf_ptr += staplen; len -= staplen;  
   
                if (fFrameHandlerFunc)  
                     fFrameHandlerFunc(fFrameHandlerFuncData, fFrameType, media_timestamp, fFrameBuf, fFrameBufPos);  
                resetFrameBuf();  
           }  
           break;  
                 }  
      default:  
           putStartCode();  
           copyToFrameBuffer(buf_ptr, len);  
           isCompleteFrame = true;  
           break;  
      }  
   
      if (isCompleteFrame) {  
           if (fFrameHandlerFunc)  
                fFrameHandlerFunc(fFrameHandlerFuncData, fFrameType, media_timestamp, fFrameBuf, fFrameBufPos);  
           resetFrameBuf();  
      }  
 }