第二次看ZLMediaKit部分的记录,有许多理解错误的地方,将进一步整理。
cd /opt/ZLMediaKit
mkdir build
cd build
cmake .. -DENABLE_WEBRTC=true -DOPENSSL_ROOT_DIR=/opt/openssl -DOPENSSL_LIBRARIES=/opt/openssl/lib
cmake --build . --target MediaServer
cd /opt/ZLMediaKit/release/linux/Debug
./MediaServer
e:
cd e:\Demo\CGAvioRead\Debug
ffmpeg -re -stream_loop -1 -i d:/H264_AAC_2021-02-10_1080P.mp4 -vcodec copy -acodec copy -f flv -y rtmp://10.10.14.103:1935/live/Camera_00002
ffmpeg -re -stream_loop -1 -i d:/H264_AAC_2021-02-10_1080P.mp4 -vcodec copy -acodec copy -f flv -y rtmp://192.168.0.107:1935/live/Camera_00002
ffmpeg -re -stream_loop -1 -i e:/H264_AAC_2021-02-10_1080P.mp4 -vcodec copy -acodec copy -f rtsp -rtsp_transport tcp rtsp://10.10.15.30:554/live/Camera_00001
1. RtmpSession::onRecv
onParseRtmp
2. RtmpProtocol::onParseRtmp
input(data, size)
3. HttpRequestSplitter::input
(index = onSearchPacketTail(ptr,_remain_data_size)) != nullptr)
4. RtmpProtocol::onSearchPacketTail
构造函数:
_next_step_func = [this](const char *data, size_t len) {
return handle_C0C1(data, len);
};
auto ret = next_step_func(data, len);
5. RtmpProtocol::handle_C0C1
if (data[0] != HANDSHAKE_PLAINTEXT)
对C0的判断,为0x03
handle_C1_complex(data);
编译时ENABLE_OPENSSL打开。
6. RtmpProtocol::handle_C1_complex
C1的方式为schema1:
c1s1 schema0
time: 4bytes
version: 4bytes
digest: 764bytes
key: 764bytes
RtmpProtocol::get_C1_digest() //skip c0,time,version
得到digest,764bytes digest结构:
offset: 4bytes
random-data: (offset)bytes
digest-data: 32bytes
random-data: (764-4-offset-32)bytes
check_C1_Digest:验证digest.
Send_complex_S0S1S2(1, digest);
7. RtmpProtocol::send_complex_S0S1S2
(1)//发送S0
char handshake_head = HANDSHAKE_PLAINTEXT;
onSendRawData(obtainBuffer(&handshake_head, 1));
(2)//发送S1
memcpy(s1.zero, "\x04\x05\x00\x01", 4);为版本号
c1s1 schema1
time: 4bytes
version: 4bytes
digest: 764bytes
key: 764bytes
get_C1_digest(s1.random, &digestPos);
//将digest加入,并发送
memcpy(digestPos, s1_digest.data(), s1_digest.size());
onSendRawData(obtainBuffer((char *) &s1, sizeof(s1)));
(3)//发送S2
生成key和digest,然后发送。
(4)等待C2
handle_C2(data, len)
8. RtmpProtocol::handle_C2
未过多进行处理。握手结束,进入命令模。
9. RtmpProtocol::handle_rtmp
(1)static constexpr size_t HEADER_LENGTH[] = {12, 8, 4, 1};
auto header_len = HEADER_LENGTH[header->fmt];
得到RTMP header的长度。
(2) switch (_now_chunk_id)
对编码块流进一步处理。ID 0、1、2作为保留。0,两个字节表示,第一个字节+64;1,三个字节表示,(第三个字节) * 256 + 第二个字节 + 64);2表示低层协议消息。3-63,表示完整的流ID。这个switch一般不会走到。
(3)handle_chunk(std::move(now_packet));
10. RtmpProtocol::handle_chunk
(1)RtmpPacket中的变量
bool is_abs_stamp;
uint8_t type_id;
uint32_t time_stamp;
uint32_t ts_field;
uint32_t stream_index;
uint32_t chunk_id;
size_t body_size;
toolkit::BufferLikeString buffer;
bool is_abs_stamp;
uint8_t type_id;
uint32_t time_stamp;
uint32_t ts_field;
uint32_t stream_index;
uint32_t chunk_id;
size_t body_size;
toolkit::BufferLikeString buffer;
(2)MSG_SET_CHUNK
type_id:1,body_size:4
来表示chunk_size的长度,如ea 60:60000
(3) MSG_WIN_SIZE
type_id:5,body_size:4
这个在播放时为发送。这个值应在32 * 1024U-1280 * 1024U之间。客户端收到大于这个字节的数据,要向服务器发送ACK消息。
(4) MSG_SET_PEER_BW
type_id:6,body_size:5
4个字节的字节的大小,1个字节的类型。未调试到。
(5)MSG_AGGREGAT
将包含子包的进行拆分。未调试到。
(6)MSG_USER_CONTROL
未调试到。包含有多一个事件信息,从代码来看,一般前2个字节是事件的类型,接着的4个字节是内容。
(7)MSG_ACK
Acknowledgement。确认信息。未进行过多的处理。
(8)其他的消息
- 收到设定的字节,回复确认信息。
- 基他的交由onRtmpChunk处理。
11. RtmpSession::onRtmpChunk
分为三种类型处理:
- MSG_CMD、MSG_CMD3由onProcessCmd(12)处理。
- MSG_DATA、MSG_DATA3由(13)解析。
- MSG_AUDIO、MSG_VIDEO由(14)解析。
12. RtmpSession::onProcessCmd
与RTSP的实现方法一样。处理下列命令:
- RtmpSession::onCmd_connect--15
- RtmpSession::onCmd_createStream--16
- RtmpSession::onCmd_publish--17
- RtmpSession::onCmd_deleteStream--18
- RtmpSession::onCmd_play--19
- RtmpSession::onCmd_play2--20
- RtmpSession::onCmd_seek--21
- RtmpSession::onCmd_pause--22
- RtmpSession::onCmd_playCtrl--23
13. MSG_DATA、MSG_DATA3
推流时会处理。执行setMetaData(dec);得到推流源的metadata数据。
标签:ZLMediaKit,--,inputFrame,MSG,RtmpSession,RTMP,onCmd,size From: https://www.cnblogs.com/zeliangzhang/p/17577206.html