您的位置:首页 > 其它

RTMPPacket与AVData之间的转换

2015-08-06 22:29 459 查看
1、RTMPPacket的结构:

typedef struct RTMPPacket

  {

    uint8_t m_headerType;

    uint8_t m_packetType;

    uint8_t m_hasAbsTimestamp; /* timestamp absolute or relative? */

    int m_nChannel;

    uint32_t m_nTimeStamp; /* timestamp */

    int32_t m_nInfoField2; /* last 4 bytes in a long header */

    uint32_t m_nBodySize;

    uint32_t m_nBytesRead;

    RTMPChunk *m_chunk;

    char *m_body;

  } RTMPPacket;

typedef struct RTMPChunk

  {

    int c_headerSize;

    int c_chunkSize;

    char *c_chunk;

    char c_header[RTMP_MAX_HEADER_SIZE];

  } RTMPChunk;

#define RTMP_MAX_HEADER_SIZE 18

2、AVData是一个类,它的数据成员:

private:
unsigned char*
m_pData;

    int
m_nDataSize;
int m_nMaxDataSize;
int m_nHeadSize;

    uint64_t
m_nTimeTick;
bool m_bKeyFrame;
bool m_bEncode;
int m_nWidth;
int m_nHeight;
int m_nStreamType;
//1 视频 0 音频
int m_nAVType;
bool m_bSign;
int m_nDuration;
std::string
m_strIndexInfo;

3、音视频数据转AVData

bool SetData(int nAVType, unsigned char* pData, int nSize, uint64_t timetick, unsigned short nType, 
bool bkeyFrame, unsigned short nCodeID, unsigned short nWidth, 
unsigned short nHeight, bool bEncode, bool bClone = true)

{
m_nDuration = 0;
m_nAVType = nAVType;
m_bKeyFrame = bkeyFrame;

if (bClone)
{
if (em_avdata_video == m_nAVType)
{
m_nHeadSize = 3;
if (bkeyFrame)
{
m_nHeadSize = 8;
}

m_nDataSize = nSize + m_nHeadSize;
int nLen = m_nDataSize;

if (NULL != m_pData)
{
if (m_nDataSize > m_nMaxDataSize)
{
m_pData = (unsigned char*)realloc(m_pData, m_nDataSize);
m_nMaxDataSize = m_nDataSize;
}
}
else
{
m_pData = (unsigned char *)malloc(nLen);
m_nMaxDataSize = m_nDataSize;
}

if (m_pData == NULL)
{
return false;
}

memcpy(m_pData+m_nHeadSize,pData,nSize);
*(bool*)(m_pData) = bkeyFrame;
unsigned short nTick = (unsigned short)(timetick%100);
*(unsigned short*)(m_pData+1) = htons(nTick);

if (bkeyFrame)
{
*(unsigned char*)(m_pData+3) = nCodeID;
*(unsigned short*)(m_pData+4) = htons(nWidth);
*(unsigned short*)(m_pData+6) = htons(nHeight);
}
}
else if (em_avdata_audio == m_nAVType)
{
m_nHeadSize = 10;
m_nDataSize = nSize + m_nHeadSize;
short int nChannels = nType;
short int nSample_rate = nWidth;
short int nBit = nHeight;
short int nTick = (short int)timetick;
int nLen = m_nDataSize;
m_pData = (unsigned char *)malloc(nLen);
memcpy(m_pData+m_nHeadSize,pData,nSize);
*(unsigned short*)(m_pData) = htons(nCodeID);
*(unsigned short*)(m_pData+2) = htons(nChannels);
*(unsigned short*)(m_pData+4) = htons(nSample_rate);
*(unsigned short*)(m_pData+6) = htons(nBit);
*(unsigned short*)(m_pData+8) = htons(nTick);
}
}
else
{
m_nHeadSize = 0;
m_nDataSize = nSize;
m_pData = pData;
}

m_nTimeTick = timetick;
m_bEncode = bEncode;
m_nStreamType = nType;

m_nHeight = nHeight;
m_nWidth = nWidth;

return true;

}

这个函数相当于将数据pData根据不同的类型增加了一个头部

视频:0:bKeyFrame,1~2:timetick(3:codeid,4~5:nWidth,6~7:nHeight)

音频:0~1:codeid,2~3:nChannels(nType),4~5:samerate(nWidth),6~7nBit(nHeigt),8~9:timetick

4、AVData转unsigned int nPacketType,unsigned char *data,unsigned int size,unsigned int nTimestamp

void libRtmpProxy::SendRtmpQueue()

{
AVData* pAVData = m_pDataPool->GetDataBuffer();
if (pAVData)
{
refguard g(pAVData);
unsigned char* pBuff = pAVData->GetAVData();

int nBufLen = pAVData->GetAVDataSize(); 
int nType = pAVData->GetAVDataType();
unsigned int unTimestamp = pAVData->GetTimeTick();
bool bIsKeyFrame = pAVData->IsKeyFrame();

unsigned char *body = new unsigned char[nBufLen+9];

int i = 0;
if(bIsKeyFrame)
{
body[i++] = 0x17;// 1:Iframe  7:AVC
}
else
{
body[i++] = 0x27;// 2:Pframe  7:AVC
}
body[i++] = 0x01;// AVC NALU
body[i++] = 0x00;
body[i++] = 0x00;
body[i++] = 0x00;

// NALU size
body[i++] = nBufLen>>24;
body[i++] = nBufLen>>16;
body[i++] = nBufLen>>8;
body[i++] = nBufLen&0xff;

// NALU data
memcpy(&body[i],pBuff,nBufLen);

int nPacketType = RTMP_PACKET_TYPE_VIDEO;
if (nType == 0)
{
nPacketType = RTMP_PACKET_TYPE_AUDIO;
}

bool bRet = SendPacket(nPacketType, body,i+nBufLen, unTimestamp);

delete[] body;
}

}

这个函数相当于取出AVData的属性,将原来加入的头部删除,增加了一个9字节长度的头部

(音频也有I、P帧吗?)

5、由属性转为RTMPPacket

int libRtmpProxy::SendPacket(unsigned int nPacketType,unsigned char *data,unsigned int size,unsigned int nTimestamp)

{
RTMPPacket packet;
RTMPPacket_Reset(&packet);
RTMPPacket_Alloc(&packet,size);

packet.m_packetType = nPacketType;
packet.m_nChannel = 0x04;  
packet.m_headerType = RTMP_PACKET_SIZE_LARGE;  
packet.m_nTimeStamp = nTimestamp;  
packet.m_nInfoField2 = m_pRtmp->m_stream_id;
packet.m_nBodySize = size;
memcpy(packet.m_body,data,size);

int nRet = RTMP_SendPacket(m_pRtmp,&packet,0);

RTMPPacket_Free(&packet);

return nRet;

}

此函数向packet直接赋属性值,copy第4步准备的整个包(包括头部)

6、RTMPPacket转AVData的思路

6.1直接得到属性,从头部可取得属性,删除9字节的头部,
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: