rtmp数据封装一-块(chunk)

简介

由于一帧音视频数据有时候会很大,比如几十M甚至更大。但是为了方便在网络上传输,需要把数据拆分成一个个较小的块,这里称之为消息块(Chunk)。常见的是每块大小为4000 byte左右。

Chunk的结构如下:

  • [Chunk Basic Header]
  • [Chunk Message Header]
  • [Extended TimeStamp]
  • [Chunk Data]

[Chunk Basic Header][Chunk Message Header][Extended TimeStamp] 3个合在一起都是 Chunk Header。

struct rtmp_chunk_header_t
{
    uint8_t fmt; // RTMP_CHUNK_TYPE_XXX
    uint32_t cid; // chunk stream id(22-bits)

    uint32_t timestamp; // delta(24-bits) / extended timestamp(32-bits)

    uint32_t length; // message length (24-bits)
    uint8_t type; // message type id

    uint32_t stream_id; // message stream id
};

Chunk Basic Header

Header Type + Channel ID 组成,长度在1~3个字节之间

Header Type (FMT)

FMT决定[Chunk Message Header]的长度,取值有0~3,对应关系是:

  • 0 : 11 bytes
  • 1 : 7 bytes
  • 2 : 3 bytes
  • 3 : 0 byte

Channel ID

通道id号常用的有:

  • 2 : Protocol Control Messages (1,2,3,5,6) & User Control Messages Event (4)
  • 3 : Invoke通道,这个通道适用的消息很多,比较灵活, connect, create_stream, release_stream, delete_stream, fcpublish, fcunpublish, publish, play, pause, seek, send_get_stream_length, 以及script脚本数据
  • 4 : Audio通道
  • 5 : Vidio通道
  • 6 : 可以传输自定义的媒体流通道

Chunk Basic Header的组成

Chunk Basic Header的长度由[Channel ID]决定,对应关系是

if(cid>=(64+255))
    size=3;
else if(cid>=64)
    size=2;
else
    size=1;

Chunk Basic Header

/*
 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
|fmt|   cs id   |
+-+-+-+-+-+-+-+-+

 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|fmt|     0     |   cs id - 64  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|fmt|     1     |          cs id - 64           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/

计算公式如下:

/**
* out        :    Basic Header Data
* fmt        :    Header Type
* id        :    Channel ID
* return    :    Basic Header Data Length
*/
int rtmp_chunk_basic_header_write(uint8_t* out, uint8_t fmt, uint32_t id)
{
    if (id >= 64 + 255)
    {
        *out++ = (fmt << 6) | 1;
        *out++ = (uint8_t)((id - 64) & 0xFF);
        *out++ = (uint8_t)(((id - 64) >> 8) & 0xFF);
        return 3;
    }
    else if (id >= 64)
    {
        *out++ = (fmt << 6) | 0;
        *out++ = (uint8_t)(id - 64);
        return 2;
    }
    else
    {
        *out++ = (fmt << 6) | (uint8_t)id;
        return 1;
    }
}

Chunk Message Header

前面有提到,FMT决定[Chunk Message Header]的长度,取值有0~3,对应关系是:

  • 0 : 11 bytes , timestamp(3) + length(3) + stream type(1) + stream id(4)
  • 1 : 7 bytes , timestamp(3) + length(3) + stream type(1)
  • 2 : 3 bytes , timestamp(3)
  • 3 : 0 byte

  • timestamp是时间戳,3个byte,超过0xFFFFFF时填0xFFFFFF,然后使用Extended TimeStamp

  • length是帧长度,3个byte
  • stream type是[Channel ID],一个byte

Extended TimeStamp

补充的时间戳,在Chunk Message Header的时间戳3个byte不够时才使用,4byte

Chunk Data

块数据,比如一帧数据长度为8080byte,以4000 byte拆分,第一个Chunk的Chunk Data就是前4000byte,第二个Chunk的Chunk Data就是第4001byte~8000byte,第三个Chunk的Chunk Data就是剩下的80byte。