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
#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"
#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;
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;
라벨:
스트리밍,
rtp,
rtp header parse
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();
}
}
피드 구독하기:
글 (Atom)