linux 下librtmp源码,RTMPdump(libRTMP) 源代码分析 6: 建立一个流媒体连接 (NetStream部分 1...

===============================

多余的话不多说,下面先来看看RTMP_ConnectStream(),该函数主要用于在NetConnection基础上建立一个NetStream。

RTMP_ConnectStream()

//创建流

int

RTMP_ConnectStream(RTMP *r, intseekTime)

{

RTMPPacket packet = { 0 };

if(seekTime > 0)

r->Link.seekTime = seekTime;

r->m_mediaChannel = 0;

while(!r->m_bPlaying && RTMP_IsConnected(r) && RTMP_ReadPacket(r, &packet))

{

if(RTMPPacket_IsReady(&packet))

{

if(!packet.m_nBodySize)

continue;

if((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO) ||

(packet.m_packetType == RTMP_PACKET_TYPE_VIDEO) ||

(packet.m_packetType == RTMP_PACKET_TYPE_INFO))

{

RTMP_Log(RTMP_LOGWARNING, "Received FLV packet before play()! Ignoring.");

RTMPPacket_Free(&packet);

continue;

}

//处理Packet!

//----------------

r->dlg->AppendCInfo("建立网络流:处理收到的数据。开始处理收到的数据");

//-----------------------------

RTMP_ClientPacket(r, &packet);

//----------------

r->dlg->AppendCInfo("建立网络流:处理收到的数据。处理完毕,清除数据。");

//-----------------------------

RTMPPacket_Free(&packet);

}

}

returnr->m_bPlaying;

}

//创建流

int

RTMP_ConnectStream(RTMP *r, int seekTime)

{

RTMPPacket packet = { 0 };

if (seekTime > 0)

r->Link.seekTime = seekTime;

r->m_mediaChannel = 0;

while (!r->m_bPlaying && RTMP_IsConnected(r) && RTMP_ReadPacket(r, &packet))

{

if (RTMPPacket_IsReady(&packet))

{

if (!packet.m_nBodySize)

continue;

if ((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO) ||

(packet.m_packetType == RTMP_PACKET_TYPE_VIDEO) ||

(packet.m_packetType == RTMP_PACKET_TYPE_INFO))

{

RTMP_Log(RTMP_LOGWARNING, "Received FLV packet before play()! Ignoring.");

RTMPPacket_Free(&packet);

continue;

}

//处理Packet!

//----------------

r->dlg->AppendCInfo("建立网络流:处理收到的数据。开始处理收到的数据");

//-----------------------------

RTMP_ClientPacket(r, &packet);

//----------------

r->dlg->AppendCInfo("建立网络流:处理收到的数据。处理完毕,清除数据。");

//-----------------------------

RTMPPacket_Free(&packet);

}

}

return r->m_bPlaying;

}

乍一看,这个函数的代码量好像挺少的,实际上不然,其复杂度还是挺高的。我觉得比RTMP_Connect()要复杂不少。

其关键就在于这个While()循环。首先,循环的三个条件都满足,就能进行循环。只有出错或者建立网络流(NetStream)的步骤完成后,才能跳出循环。

在这个函数中有两个函数尤为重要:

RTMP_ReadPacket()

RTMP_ClientPacket()

第一个函数的作用是读取通过Socket接收下来的消息(Message)包,但是不做任何处理。第二个函数则是处理消息(Message),并做出响应。这两个函数结合,就可以完成接收消息然后响应消息的步骤。

下面来开一下RTMP_ReadPacket():

//读取收下来的Chunk

int

RTMP_ReadPacket(RTMP *r, RTMPPacket *packet)

{

//packet 存读取完后的的数据

//Chunk Header最大值18

uint8_t hbuf[RTMP_MAX_HEADER_SIZE] = { 0 };

//header 指向的是从Socket中收下来的数据

char*header = (char*)hbuf;

intnSize, hSize, nToRead, nChunk;

intdidAlloc = FALSE;

RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d", __FUNCTION__, r->m_sb.sb_socket);

//收下来的数据存入hbuf

if(ReadN(r, (char*)hbuf, 1) == 0)

{

RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header", __FUNCTION__);

returnFALSE;

}

//块类型fmt

packet->m_headerType = (hbuf[0] & 0xc0) >> 6;

//块流ID(2-63)

packet->m_nChannel = (hbuf[0] & 0x3f);

header++;

//块流ID第1字节为0时,块流ID占2个字节

if(packet->m_nChannel == 0)

{

if(ReadN(r, (char*)&hbuf[1], 1) != 1)

{

RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header 2nd byte",

__FUNCTION__);

returnFALSE;

}

//计算块流ID(64-319)

packet->m_nChannel = hbuf[1];

packet->m_nChannel += 64;

header++;

}

//块流ID第1字节为0时,块流ID占3个字节

elseif(packet->m_nChannel == 1)

{

inttmp;

if(ReadN(r, (char*)&hbuf[1], 2) != 2)

{

RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header 3nd byte",

__FUNCTION__);

returnFALSE;

}

tmp = (hbuf[2] <

//计算块流ID(64-65599)

packet->m_nChannel = tmp + 64;

RTMP_Log(RTMP_LOGDEBUG, "%s, m_nChannel: %0x", __FUNCTION__, packet->m_nChannel);

header += 2;

}

//ChunkHeader的大小(4种)

nSize = packetSize[packet->m_headerType];

if(nSize == RTMP_LARGE_HEADER_SIZE)

packet->m_hasAbsTimestamp = TRUE; //11字节的完整ChunkMsgHeader的TimeStamp是绝对值

elseif(nSize 

{

if(r->m_vecChannelsIn[packet->m_nChannel])

memcpy(packet, r->m_vecChannelsIn[packet->m_nChannel],

sizeof(RTMPPacket));

}

nSize--;

if(nSize > 0 && ReadN(r, header, nSize) != nSize)

{

RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header. type: %x",

__FUNCTION__, (unsigned int)hbuf[0]);

returnFALSE;

}

hSize = nSize + (header - (char*)hbuf);

if(nSize >= 3)

{

//TimeStamp(注意 BigEndian to SmallEndian)(11,7,3字节首部都有)

packet->m_nTimeStamp = AMF_DecodeInt24(header);

//消息长度(11,7字节首部都有)

if(nSize >= 6)

{

packet->m_nBodySize = AMF_DecodeInt24(header + 3);

packet->m_nBytesRead = 0;

RTMPPacket_Free(packet);

//(11,7字节首部都有)

if(nSize > 6)

{

//Msg type ID

packet->m_packetType = header[6];

//Msg Stream ID

if(nSize == 11)

packet->m_nInfoField2 = DecodeInt32LE(header + 7);

}

}

//Extend TimeStamp

if(packet->m_nTimeStamp == 0xffffff)

{

if(ReadN(r, header + nSize, 4) != 4)

{

RTMP_Log(RTMP_LOGERROR, "%s, failed to read extended timestamp",

__FUNCTION__);

returnFALSE;

}

packet->m_nTimeStamp = AMF_DecodeInt32(header + nSize);

hSize += 4;

}

}

RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)hbuf, hSize);

if(packet->m_nBodySize > 0 && packet->m_body == NULL)

{

if(!RTMPPacket_Alloc(packet, packet->m_nBodySize))

{

RTMP_Log(RTMP_LOGDEBUG, "%s, failed to allocate packet", __FUNCTION__);

returnFALSE;

}

didAlloc = TRUE;

packet->m_headerType = (hbuf[0] & 0xc0) >> 6;

}

nToRead = packet->m_nBodySize - packet->m_nBytesRead;

nChunk = r->m_inChunkSize;

if(nToRead 

nChunk = nToRead;

if(packet->m_chunk)

{

packet->m_chunk->c_headerSize = hSize;

memcpy(packet->m_chunk->c_header, hbuf, hSize);

packet->m_chunk->c_chunk = packet->m_body + packet->m_nBytesRead;

packet->m_chunk->c_chunkSize = nChunk;

}

if(ReadN(r, packet->m_body + packet->m_nBytesRead, nChunk) != nChunk)

{

RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet body. len: %lu",

__FUNCTION__, packet->m_nBodySize);

returnFALSE;

}

RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)packet->m_body + packet->m_nBytesRead, nChunk);

packet->m_nBytesRead += nChunk;

if(!r->m_vecChannelsIn[packet->m_nChannel])

r->m_vecChannelsIn[packet->m_nChannel] = (RTMPPacket *) malloc(sizeof(RTMPPacket));

memcpy(r->m_vecChannelsIn[packet->m_nChannel], packet, sizeof(RTMPPacket));

//读取完毕

if(RTMPPacket_IsReady(packet))

{

if(!packet->m_hasAbsTimestamp)

packet->m_nTimeStamp += r->m_channelTimestamp[packet->m_nChannel];

r->m_channelTimestamp[packet->m_nChannel] = packet->m_nTimeStamp;

r->m_vecChannelsIn[packet->m_nChannel]->m_body = NULL;

r->m_vecChannelsIn[packet->m_nChannel]->m_nBytesRead = 0;

r->m_vecChannelsIn[packet->m_nChannel]->m_hasAbsTimestamp = FALSE;

}

else

{

packet->m_body = NULL;

}

returnTRUE;

}

//读取收下来的Chunk

int

RTMP_ReadPacket(RTMP *r, RTMPPacket *packet)

{

//packet 存读取完后的的数据

//Chunk Header最大值18

uint8_t hbuf[RTMP_MAX_HEADER_SIZE] = { 0 };

//header 指向的是从Socket中收下来的数据

char *header = (char *)hbuf;

int nSize, hSize, nToRead, nChunk;

int didAlloc = FALSE;

RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d", __FUNCTION__, r->m_sb.sb_socket);

//收下来的数据存入hbuf

if (ReadN(r, (char *)hbuf, 1) == 0)

{

RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header", __FUNCTION__);

return FALSE;

}

//块类型fmt

packet->m_headerType = (hbuf[0] & 0xc0) >> 6;

//块流ID(2-63)

packet->m_nChannel = (hbuf[0] & 0x3f);

header++;

//块流ID第1字节为0时,块流ID占2个字节

if (packet->m_nChannel == 0)

{

if (ReadN(r, (char *)&hbuf[1], 1) != 1)

{

RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header 2nd byte",

__FUNCTION__);

return FALSE;

}

//计算块流ID(64-319)

packet->m_nChannel = hbuf[1];

packet->m_nChannel += 64;

header++;

}

//块流ID第1字节为0时,块流ID占3个字节

else if (packet->m_nChannel == 1)

{

int tmp;

if (ReadN(r, (char *)&hbuf[1], 2) != 2)

{

RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header 3nd byte",

__FUNCTION__);

return FALSE;

}

tmp = (hbuf[2] << 8) + hbuf[1];

//计算块流ID(64-65599)

packet->m_nChannel = tmp + 64;

RTMP_Log(RTMP_LOGDEBUG, "%s, m_nChannel: %0x", __FUNCTION__, packet->m_nChannel);

header += 2;

}

//ChunkHeader的大小(4种)

nSize = packetSize[packet->m_headerType];

if (nSize == RTMP_LARGE_HEADER_SIZE)

packet->m_hasAbsTimestamp = TRUE; //11字节的完整ChunkMsgHeader的TimeStamp是绝对值

else if (nSize < RTMP_LARGE_HEADER_SIZE)

{

if (r->m_vecChannelsIn[packet->m_nChannel])

memcpy(packet, r->m_vecChannelsIn[packet->m_nChannel],

sizeof(RTMPPacket));

}

nSize--;

if (nSize > 0 && ReadN(r, header, nSize) != nSize)

{

RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header. type: %x",

__FUNCTION__, (unsigned int)hbuf[0]);

return FALSE;

}

hSize = nSize + (header - (char *)hbuf);

if (nSize >= 3)

{

//TimeStamp(注意 BigEndian to SmallEndian)(11,7,3字节首部都有)

packet->m_nTimeStamp = AMF_DecodeInt24(header);

//消息长度(11,7字节首部都有)

if (nSize >= 6)

{

packet->m_nBodySize = AMF_DecodeInt24(header + 3);

packet->m_nBytesRead = 0;

RTMPPacket_Free(packet);

//(11,7字节首部都有)

if (nSize > 6)

{

//Msg type ID

packet->m_packetType = header[6];

//Msg Stream ID

if (nSize == 11)

packet->m_nInfoField2 = DecodeInt32LE(header + 7);

}

}

//Extend TimeStamp

if (packet->m_nTimeStamp == 0xffffff)

{

if (ReadN(r, header + nSize, 4) != 4)

{

RTMP_Log(RTMP_LOGERROR, "%s, failed to read extended timestamp",

__FUNCTION__);

return FALSE;

}

packet->m_nTimeStamp = AMF_DecodeInt32(header + nSize);

hSize += 4;

}

}

RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)hbuf, hSize);

if (packet->m_nBodySize > 0 && packet->m_body == NULL)

{

if (!RTMPPacket_Alloc(packet, packet->m_nBodySize))

{

RTMP_Log(RTMP_LOGDEBUG, "%s, failed to allocate packet", __FUNCTION__);

return FALSE;

}

didAlloc = TRUE;

packet->m_headerType = (hbuf[0] & 0xc0) >> 6;

}

nToRead = packet->m_nBodySize - packet->m_nBytesRead;

nChunk = r->m_inChunkSize;

if (nToRead < nChunk)

nChunk = nToRead;

if (packet->m_chunk)

{

packet->m_chunk->c_headerSize = hSize;

memcpy(packet->m_chunk->c_header, hbuf, hSize);

packet->m_chunk->c_chunk = packet->m_body + packet->m_nBytesRead;

packet->m_chunk->c_chunkSize = nChunk;

}

if (ReadN(r, packet->m_body + packet->m_nBytesRead, nChunk) != nChunk)

{

RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet body. len: %lu",

__FUNCTION__, packet->m_nBodySize);

return FALSE;

}

RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)packet->m_body + packet->m_nBytesRead, nChunk);

packet->m_nBytesRead += nChunk;

if (!r->m_vecChannelsIn[packet->m_nChannel])

r->m_vecChannelsIn[packet->m_nChannel] = (RTMPPacket *) malloc(sizeof(RTMPPacket));

memcpy(r->m_vecChannelsIn[packet->m_nChannel], packet, sizeof(RTMPPacket));

//读取完毕

if (RTMPPacket_IsReady(packet))

{

if (!packet->m_hasAbsTimestamp)

packet->m_nTimeStamp += r->m_channelTimestamp[packet->m_nChannel];

r->m_channelTimestamp[packet->m_nChannel] = packet->m_nTimeStamp;

r->m_vecChannelsIn[packet->m_nChannel]->m_body = NULL;

r->m_vecChannelsIn[packet->m_nChannel]->m_nBytesRead = 0;

r->m_vecChannelsIn[packet->m_nChannel]->m_hasAbsTimestamp = FALSE;

}

else

{

packet->m_body = NULL;

}

return TRUE;

}

在这里要注意的是,接收下来的实际上是块(Chunk)而不是消息(Message),因为消息(Message)在网络上传播的时候,实际上要分割成块(Chunk)。

这里解析的就是块(Chunk)

具体的解析代码我就不多说了,直接参考RTMP协议规范就可以了,一个字节一个字节的解析就OK了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值