zoukankan      html  css  js  c++  java
  • RTMP协议中的Chunk Stream ID (CID)的作用

    一、协议分层

      RTMP包是以Message的结构封装的,结构如下所示:

      

      

      1)Message Type ID在1-7的消息用于协议控制,这些消息一般是RTMP协议自身管理要使用的消息,用户一般情况下无需操作其中的数据。

        Message Type ID为8,9的消息分别用于传输音频和视频数据。Message Type ID为15-20的消息用于发送AMF编码的命令,负责用户与服务器之间的交互,比如播放,暂停等等。

      2)StreamID是音视频流的唯一ID, 一路流如果既有音频包又有视频包,那么这路流音频包的StreamID和他视频包的StreamID相同。

      

      一个Message大小不一,音频视频的Message往往差异较大,为了充分利用网络,需要将一个大的Message中的Body部分拆分到一个或者多个Chunk中

      Chunk结构:

      

      在拆分到多个Chunk中的时候,第一个Chunk携带完整的Message Header信息

      因为一个流当中可以传输多个Chunk,那么多个Chunk怎么标记同属于一个Message的呢?

      是通过Chunk Stream ID区分的,同一个Chunk Stream ID必然属于同一个Message

      

      SRS中的Chunk接收和拼接成Message的代码可以证明:

      

    int SrsProtocol::recv_interlaced_message(SrsCommonMessage** pmsg)
    {
        int ret = ERROR_SUCCESS;
        
        // chunk stream basic header.
        char fmt = 0;
        int cid = 0;
        if ((ret = read_basic_header(fmt, cid)) != ERROR_SUCCESS) {
            if (ret != ERROR_SOCKET_TIMEOUT && !srs_is_client_gracefully_close(ret)) {
                srs_error("read basic header failed. ret=%d", ret);
            }
            return ret;
        }
        srs_verbose("read basic header success. fmt=%d, cid=%d", fmt, cid);
        
        // the cid must not negative.
        srs_assert(cid >= 0);
        
        // get the cached chunk stream.
        SrsChunkStream* chunk = NULL;
        
        // use chunk stream cache to get the chunk info.
        // @see https://github.com/ossrs/srs/issues/249
        if (cid < SRS_PERF_CHUNK_STREAM_CACHE) {
            // chunk stream cache hit.
            srs_verbose("cs-cache hit, cid=%d", cid);
            // already init, use it direclty
            chunk = cs_cache[cid];
            srs_verbose("cached chunk stream: fmt=%d, cid=%d, size=%d, message(type=%d, size=%d, time=%"PRId64", sid=%d)",
                chunk->fmt, chunk->cid, (chunk->msg? chunk->msg->size : 0), chunk->header.message_type, chunk->header.payload_length,
                chunk->header.timestamp, chunk->header.stream_id);
        } else {
            // chunk stream cache miss, use map.
            if (chunk_streams.find(cid) == chunk_streams.end()) {
                chunk = chunk_streams[cid] = new SrsChunkStream(cid);
                // set the perfer cid of chunk,
                // which will copy to the message received.
                chunk->header.perfer_cid = cid;
                srs_verbose("cache new chunk stream: fmt=%d, cid=%d", fmt, cid);
            } else {
                chunk = chunk_streams[cid];
                srs_verbose("cached chunk stream: fmt=%d, cid=%d, size=%d, message(type=%d, size=%d, time=%"PRId64", sid=%d)",
                    chunk->fmt, chunk->cid, (chunk->msg? chunk->msg->size : 0), chunk->header.message_type, chunk->header.payload_length,
                    chunk->header.timestamp, chunk->header.stream_id);
            }
        }
    

      

    红色的是以CID为key的一个Map,每次的第一个Chunk过来的时候,都缓存起来,下一个Chunk来了之后进行追加。

    因为TCP的有序,所以同一个Message中不同的Chunk会先后抵达。

     
  • 相关阅读:
    关于Markdown
    20. 有效的括号(栈)
    数组队列
    MySql编码、卸载、启动问题
    循环队列
    链表实现与时间复杂度分析
    栈的应用和基本实现
    使用链表实现栈
    封装动态数组类Array
    Android平台的开发环境的发展演变
  • 原文地址:https://www.cnblogs.com/doudouyoutang/p/9299704.html
Copyright © 2011-2022 走看看