Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

学习 rtmp 开发 (Part 5: rtmp protocol) #274

Open
nonocast opened this issue May 18, 2022 · 0 comments
Open

学习 rtmp 开发 (Part 5: rtmp protocol) #274

nonocast opened this issue May 18, 2022 · 0 comments
Labels

Comments

@nonocast
Copy link
Owner

nonocast commented May 18, 2022

学习rtmp协议应以adobe spec为主,网上文章和代码只能作为cookie,不要太当回事情,包括这篇,在读pdf的过程中辅以wireshark,事半功倍。

RTMP全称Real Time Messaging Protocol, 我们分别理解Messaging和Real Time。

Messaging

Spec的chapter 6 RTMP Message Formats (p21) 中说到RTMP Message设计就是用来广泛支持audio-video applications, 包括one-to-one, one-to-mang以及video-on-demand等各种应用服务。所以说Message在这里是一个高度抽象的概念,适合各种情况。

  • RTMP message 有两个部分: header和payload。
  • header 采用固定的11个字节: Message Type (1 byte)+Payload length (3 bytes) + Timestamp (4 bytes) + Stream ID (3 bytes)
  • Message Type 采用1个字节可以支持到255个type,RTMP给出的类型主要包括3大类:
    • Protocol Control Messages
      • Set Chunk Size (1)
      • Abort Message (2)
      • Acknowledgement (3)
      • User Control Message (4)
        • Stream Begin (0)
        • Stream EOF (1)
        • StreamDry (2)
        • SetBufferLength (3)
        • StreamIsRecorded (4)
        • PingRequest (6)
        • PingResponse (7)
      • Window Acknowledgment Size (5)
      • Set Peer Bandwidth (6)
    • RTMP Media Message
      • Audio Message (8)
      • Video Message (9)
    • RTMP Command Message
      • Command Message (20, 17): RPC, 20采用AMF0, 17采用AMF3
        • NetConnection commands: connect, call, close, createStream
        • NetStream commands: play, play2, deleteStream, closeStream, receiveAudio, receiveVideo, pulish, seek, pause
      • Data Message (18, 15): Metadata or any user data to the peer. 18采用AMF0, 15采用AMF3
      • Shared Object Message (19, 16): A shared object is a Flash object (a collection of name value pairs) , 各端同步数据
      • Aggregate Message (22)
  • Timestamp: Time in milliseconds at which the data in this message applied.
  • Stream ID
    • Protocol Control Messages MUST stream ID =0,且 chunk stream ID 2
    • Media Messages走的Stream ID为client通过createStream创建后得到Stream ID
    • Command Message中NetConnection采用默认的stream ID 0, 后面stream的play, publish中通过stream name告诉server, 但同时也会设置对应的stream id

Real Time

所以Real Time就是对应chunk,将Message拆分成多个chunk进行传输,wireshark抓到的一个个RTMP packet就是chunk, chunk通过拆分message后可以根据消息的timestamp和优先级排序进行发送,比如Protocol Control Message就会优先在Media Message chunk之前发送。

  • Chunk 有2个部分:Chunk Header 和 Chunk Data
  • Chunk Header 有3部分组成:
    • Basic Header (1 to 3 bytes)
    • Message Header (0, 3, 7, or 11 bytes)
    • Extended Timestamp (0 or 4 bytes)
  • Chunk Data (variable size): The payload of this chunk, up to the configured maximum chunk size.

几点说明:

  • Basic Header的开头2个bit表示fmt, 决定了Chunk Message Header的format

    • 0x00 对应 Type 0, 即 Chunk Message Header (0 byte)
    • 0x01 对应 Type 1, 即 Chunk Message Header (3 bytes)
    • 0x10 对应 Type 2, 即 Chunk Message Header (7 bytes)
    • 0x11 对应 Type 3, 即 Chunk Message Header (11 bytes)
  • 具体含义和sample在Spec都有说明,无非就是为了重复的audio,video时尽可能节省byte

  • Basic Header到底长度由csid (chunk stream id) 的大小决定,spec说协议保留0,1,2这3个csid,实现时可以用到3-65599共65597个csid,An implementation SHOULD use the smallest representation that can hold the ID. 如果csid控制在63以内则只需要一个字节(fmt+csid),如果64-319则采用2个字节,更大的话就用3个字节,实践中basic header都是1个字节。

  • csid的唯一原则就是一个相同的message在拆分成多个chunk时采用唯一的csid,否则后续无法还原成原始message,协议并没有规定如何使用csid,你自己看着办,反正我支持65599个,我能想到的是如果一个server同时支持10000个rtmp流并发,且每个video message都大于max chunk size,则确实需要10000个csid来对应,否则关联不上。

Media Message Payload

RTMP Spec中没有描述audio和video的message payload,这个就需要参考 Adobe Video File Format Specification Version 10

FLV的Tag Header完美对应Message Header:

  • TagType (UI8): 对应 Message Type (1 byte)
  • DateSize (UI24): 对应 Length (3 bytes)
  • Timestamp (UI24), Timestamp Extended (UI8): 对应 Timestamp (4 bytes)
  • StreamID (UI24): Always 0. 表示flv只关联一个stream,保留这个字段就是为了struct reuse

所以FLV录制可以理解为如下2个步骤:

  • 构建一个FLV Header

  • 然后将RTMP audio message (8), video message (9), data message (18, AMF0)3个类型的消息直接append到flv文件,然后跟一个PreviousTagSize

  • 最后就形成 FLV Header - PreviousTagSize(0) - data message - PreviousTagSize(1) - audio - PreviousTagSize(2) - video - PreviousTagSize(3) 一路下去

  • RTMP video payload对应FLV中的VIDEODATA, audio payload对应AUDIODATA,根据spec解析即可
    参考 学习 rtmp 开发 (Part 3: FLV Format) #271

扩展

很多时候我们都被Implementation所限制住,其实RTMP本身只是messaging protocol,并没有任何限制,比如说你完全可以通过多个stream传送多股流,或者通过command message实现让client按需推流,然后再给implementation加一个http api, 通过curl就可以直接控制推流,所以有很多想象空间。

参考文档

@nonocast nonocast added the favor label May 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant