RTMP协议命令的流程详解

一, RMTP协议的命令的

1, handshake

客户端与服务器的RTMP握手的的流程

①, 客户端发送 C0+C1 规则是

消息头一共是9个字节分别是:

cid 标志是什么命令(一个字节)时间戳timestamp(四个字节)扩展字节(四个字节)
一个字节标志是什么游戏 0X03 表示发送C0+C1四个字节时间戳 ::time(NULL)四个字节的 0X00

后面在加1537个字节的随机数

代码

	// [1+1536]
    char* c0c1;
    // [1+1536+1536]
    char* s0s1s2;
    // [1536]
    char* c2;
    c0c1 = new char[1537];
    srs_random_generate(c0c1, 1537);
    
    // plain text required.
    SrsStream stream;
    if ((ret = stream.initialize(c0c1, 9)) != ERROR_SUCCESS) {
        return ret;
    }
    stream.write_1bytes(0x03);
    stream.write_4bytes((int32_t)::time(NULL));
    stream.write_4bytes(0x00);

举例

03 61 50 b0 a8 00 00 00 00 75 da 5b 1b 46 d4 74 .aP......u.[.F.t
......
1e 55 4e 8c c2 7b 12 b8 ce 33 4e 75 be 96 36 88 .UN..{...3Nu..6.
eb                                              .               

②,服务器端先回复 S0+S1+S2一个字节cid =0X03字段

一共是3073个字节

1 + 1536+1536 = 3073

其中1536 是随机数

③, 客户端发送C2标志

客户端发送C2完成就完成RTMP的握手流程

C2规则发送

cid标志位(1byte)时间戳(4byte)S0+S1+S2+时间戳(4byte)
标志什么消息客户端的时间戳

代码

	int create_c2()
	{
	    int ret = ERROR_SUCCESS;
	    
	    if (c2) {
	        return ret;
	    }
	    
	    c2 = new char[1536];
	    srs_random_generate(c2, 1536);
	    
	    // time
	    SrsStream stream;
	    if ((ret = stream.initialize(c2, 8)) != ERROR_SUCCESS) {
	        return ret;
	    }
	    stream.write_4bytes((int32_t)::time(NULL));
	    // c2 time2 copy from s1  这边就是把S0+S1+S2的时间戳赋值过来的的4byte
	    if (s0s1s2) {
	        stream.write_bytes(s0s1s2 + 1, 4);
	    }
	    
	    return ret;
	}
    

例子


00 00 00 00 00 00 00 00 36 72 72 32 6f 77 70 2d ........6rr2owp-
....
6e 73 2d 73 73 6c 32 72 36 65 65 69 6c 65 65 73 ns-ssl2r6eeilees

下载RTMP握手流程完成了 下面就要创建流推流

2,RTMP推流命令

typedef struct RTMPChunk {
    int c_headerSize;
    int c_chunkSize;
    char *c_chunk;
    char c_header[RTMP_MAX_HEADER_SIZE];
} RTMPChunk;

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;

RTMP header 计算


int
RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue) {
    const RTMPPacket *prevPacket;
    uint32_t last = 0;
    int nSize;
    int hSize, cSize;
    char *header, *hptr, *hend, hbuf[RTMP_MAX_HEADER_SIZE], c;
    uint32_t t;
    char *buffer, *tbuf = NULL, *toff = NULL;
    int nChunkSize;
    int tlen;

    if (packet->m_nChannel >= r->m_channelsAllocatedOut) {
        int n = packet->m_nChannel + 10;
        RTMPPacket **packets = realloc(r->m_vecChannelsOut, sizeof(RTMPPacket *) * n);
        if (!packets) {
            free(r->m_vecChannelsOut);
            r->m_vecChannelsOut = NULL;
            r->m_channelsAllocatedOut = 0;
            return FALSE;
        }
        r->m_vecChannelsOut = packets;
        memset(r->m_vecChannelsOut + r->m_channelsAllocatedOut, 0,
               sizeof(RTMPPacket *) * (n - r->m_channelsAllocatedOut));
        r->m_channelsAllocatedOut = n;
    }

    prevPacket = r->m_vecChannelsOut[packet->m_nChannel];
    if (prevPacket && packet->m_headerType != RTMP_PACKET_SIZE_LARGE)
    {
        /* compress a bit by using the prev packet's attributes */
        if (prevPacket->m_nBodySize == packet->m_nBodySize && prevPacket->m_packetType == packet->m_packetType && packet->m_headerType == RTMP_PACKET_SIZE_MEDIUM)
        {
            packet->m_headerType = RTMP_PACKET_SIZE_SMALL;
        }

        if (prevPacket->m_nTimeStamp == packet->m_nTimeStamp && packet->m_headerType == RTMP_PACKET_SIZE_SMALL)
        {
            packet->m_headerType = RTMP_PACKET_SIZE_MINIMUM;
        }
        last = prevPacket->m_nTimeStamp;
    }
    // headerType --> 1 4 6
    if (packet->m_headerType > 3)    /* sanity */
    {
        RTMP_Log(RTMP_LOGERROR, "sanity failed!! trying to send header of type: 0x%02x.",
                 (unsigned char) packet->m_headerType);
        return FALSE;
    }

    nSize = packetSize[packet->m_headerType];
    hSize = nSize;
    cSize = 0;
    t = packet->m_nTimeStamp - last;

    if (packet->m_body) {
        header = packet->m_body - nSize;
        hend = packet->m_body;
    } else {
        header = hbuf + 6;
        hend = hbuf + sizeof(hbuf);
    }

    if (packet->m_nChannel > 319)
    {
        cSize = 2;
    }
    else if (packet->m_nChannel > 63)
    {
        cSize = 1;
    }
    if (cSize)
    {
        header -= cSize;
        hSize += cSize;
    }

    if (t >= 0xffffff) {
        header -= 4;
        hSize += 4;
        RTMP_Log(RTMP_LOGWARNING, "Larger timestamp than 24-bit: 0x%x", t);
    }

    hptr = header;
    c = packet->m_headerType << 6;
    switch (cSize) {
        case 0:
            c |= packet->m_nChannel;
            break;
        case 1:
            break;
        case 2:
            c |= 1;
            break;
    }
    *hptr++ = c;
    if (cSize) {
        int tmp = packet->m_nChannel - 64;
        *hptr++ = tmp & 0xff;
        if (cSize == 2)
            *hptr++ = tmp >> 8;
    }
    //时间戳
    if (nSize > 1)
    {
        hptr = AMF_EncodeInt24(hptr, hend, t > 0xffffff ? 0xffffff : t);
    }

    if (nSize > 4)
    {
        hptr = AMF_EncodeInt24(hptr, hend, packet->m_nBodySize);
        *hptr++ = packet->m_packetType;
    }

    if (nSize > 8)
        hptr += EncodeInt32LE(hptr, packet->m_nInfoField2);

    if (t >= 0xffffff)
        hptr = AMF_EncodeInt32(hptr, hend, t);

    nSize = packet->m_nBodySize;
    buffer = packet->m_body;
    nChunkSize = r->m_outChunkSize;

    RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d, size=%d", __FUNCTION__, r->m_sb.sb_socket,
             nSize);
    /* send all chunks in one HTTP request */
    if (r->Link.protocol & RTMP_FEATURE_HTTP) {
        int chunks = (nSize + nChunkSize - 1) / nChunkSize;
        if (chunks > 1) {
            tlen = chunks * (cSize + 1) + nSize + hSize;
            tbuf = malloc(tlen);
            if (!tbuf)
                return FALSE;
            toff = tbuf;
        }
    }
    while (nSize + hSize) {
        int wrote;

        if (nSize < nChunkSize)
            nChunkSize = nSize;

        RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *) header, hSize);
        RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *) buffer, nChunkSize);
        if (tbuf) {
            memcpy(toff, header, nChunkSize + hSize);
            toff += nChunkSize + hSize;
        } else {
            wrote = WriteN(r, header, nChunkSize + hSize);
            if (!wrote)
                return FALSE;
        }
        nSize -= nChunkSize;
        buffer += nChunkSize;
        hSize = 0;

        if (nSize > 0) {
            header = buffer - 1;
            hSize = 1;
            if (cSize) {
                header -= cSize;
                hSize += cSize;
            }
            if (t >= 0xffffff) {
                header -= 4;
                hSize += 4;
            }
            *header = (0xc0 | c);
            if (cSize) {
                int tmp = packet->m_nChannel - 64;
                header[1] = tmp & 0xff;
                if (cSize == 2)
                    header[2] = tmp >> 8;
            }
            if (t >= 0xffffff) {
                char *extendedTimestamp = header + 1 + cSize;
                AMF_EncodeInt32(extendedTimestamp, extendedTimestamp + 4, t);
            }
        }
    }
    if (tbuf) {
        int wrote = WriteN(r, tbuf, toff - tbuf);
        free(tbuf);
        tbuf = NULL;
        if (!wrote)
            return FALSE;
    }

    /* we invoked a remote method */
    if (packet->m_packetType == RTMP_PACKET_TYPE_INVOKE) {
        AVal method;
        char *ptr;
        ptr = packet->m_body + 1;
        AMF_DecodeString(ptr, &method);
        RTMP_Log(RTMP_LOGDEBUG, "Invoking %s", method.av_val);
        /* keep it in call queue till result arrives */
        if (queue)
        {
            int txn;
            ptr += 3 + method.av_len;
            txn = (int) AMF_DecodeNumber(ptr);
            AV_queue(&r->m_methodCalls, &r->m_numCalls, &method, txn);
        }
    }

    if (!r->m_vecChannelsOut[packet->m_nChannel])
        r->m_vecChannelsOut[packet->m_nChannel] = malloc(sizeof(RTMPPacket));
    memcpy(r->m_vecChannelsOut[packet->m_nChannel], packet, sizeof(RTMPPacket));
    return TRUE;
}


messgeheader

m_headerType:代表头节点数据有多大了 {1btye}
channel :有可能1byte和2byte
时间戳:3byte也有可能是6byte

①, connect(‘流的名称’)

协议 CID 0X03

|cid(1byte)|timestamp一般4byte有可能8字节|||

参数

appflashVerswfUrltcUrlfpadcapabilitiesaudioCodecsvideoCodecsvideoFunctionpageUrlobjectEncoding
stringstringstringstringboolintintintintstringint
流的名称版本rtmp:/ip/live/app

②, Window Acknowledgemnt Size (滑动窗口的大小)

③,Set Chunk Size (设置RTMP的Chunk最大值)

④,releaseStream(‘流的名称’)

⑤,FCPublish(‘流的名称’)

⑥, createStream()

⑦,publish(‘test’)

⑧,Video Data

⑨,Audio Data

3, RTMP哪流命令

①, connect(‘live’) C->S

②, onBWDone() S->C

③,_checkbw() C->S

④, _result() S->C

⑤, getStreamLength() C->S

⑥, play(‘test’) C->S

⑦,Set buffer Length 1, 3000ms C->S

⑧,Stream Begin 1 S->C

⑨,|RtmpSampleAccess() S->C

⑩, onStatus(‘NetStream.Data.Start’)

⑪, Video Data

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值