GO和C++代码对比,GO少个25%代码
来源:互联网 发布:灯具安装网络接单平台 编辑:程序博客网 时间:2024/03/29 14:53
C++项目:https://github.com/winlinvip/simple-rtmp-server
GO项目:https://github.com/winlinvip/go.rtmp https://github.com/winlinvip/go.srs
RTMP最底层流解析,chunk读取头信息,
GO:161行
C++: 211行
GO比C++少个50行,主要是数组操作,错误信息,返回值,这几个特点让GO的代码少。
逻辑上完全一样,从C++翻译到GO函数。
C++代码如下:
int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_size, int& mh_size){ int ret = ERROR_SUCCESS; /** * we should not assert anything about fmt, for the first packet. * (when first packet, the chunk->msg is NULL). * the fmt maybe 0/1/2/3, the FMLE will send a 0xC4 for some audio packet. * the previous packet is: * 04 // fmt=0, cid=4 * 00 00 1a // timestamp=26 *00 00 9d // payload_length=157 * 08 // message_type=8(audio) * 01 00 00 00 // stream_id=1 * the current packet maybe: * c4 // fmt=3, cid=4 * it's ok, for the packet is audio, and timestamp delta is 26. * the current packet must be parsed as: * fmt=0, cid=4 * timestamp=26+26=52 * payload_length=157 * message_type=8(audio) * stream_id=1 * so we must update the timestamp even fmt=3 for first packet. */ // fresh packet used to update the timestamp even fmt=3 for first packet. bool is_fresh_packet = !chunk->msg; // but, we can ensure that when a chunk stream is fresh, // the fmt must be 0, a new stream. if (chunk->msg_count == 0 && fmt != RTMP_FMT_TYPE0) { ret = ERROR_RTMP_CHUNK_START; srs_error("chunk stream is fresh, " "fmt must be %d, actual is %d. ret=%d", RTMP_FMT_TYPE0, fmt, ret); return ret; } // when exists cache msg, means got an partial message, // the fmt must not be type0 which means new message. if (chunk->msg && fmt == RTMP_FMT_TYPE0) { ret = ERROR_RTMP_CHUNK_START; srs_error("chunk stream exists, " "fmt must not be %d, actual is %d. ret=%d", RTMP_FMT_TYPE0, fmt, ret); return ret; } // create msg when new chunk stream start if (!chunk->msg) { chunk->msg = new SrsCommonMessage(); srs_verbose("create message for new chunk, fmt=%d, cid=%d", fmt, chunk->cid); } // read message header from socket to buffer. static char mh_sizes[] = {11, 7, 3, 0}; mh_size = mh_sizes[(int)fmt]; srs_verbose("calc chunk message header size. fmt=%d, mh_size=%d", fmt, mh_size); int required_size = bh_size + mh_size; if ((ret = buffer->ensure_buffer_bytes(skt, required_size)) != ERROR_SUCCESS) { if (ret != ERROR_SOCKET_TIMEOUT) { srs_error("read %dbytes message header failed. required_size=%d, ret=%d", mh_size, required_size, ret); } return ret; } char* p = buffer->bytes() + bh_size; // parse the message header. // see also: ngx_rtmp_recv if (fmt <= RTMP_FMT_TYPE2) { char* pp = (char*)&chunk->header.timestamp_delta; pp[2] = *p++; pp[1] = *p++; pp[0] = *p++; pp[3] = 0; // fmt: 0 // timestamp: 3 bytes // If the timestamp is greater than or equal to 16777215 // (hexadecimal 0x00ffffff), this value MUST be 16777215, and the // ‘extended timestamp header’ MUST be present. Otherwise, this value // SHOULD be the entire timestamp. // // fmt: 1 or 2 // timestamp delta: 3 bytes // If the delta is greater than or equal to 16777215 (hexadecimal // 0x00ffffff), this value MUST be 16777215, and the ‘extended // timestamp header’ MUST be present. Otherwise, this value SHOULD be // the entire delta. chunk->extended_timestamp = (chunk->header.timestamp_delta >= RTMP_EXTENDED_TIMESTAMP); if (chunk->extended_timestamp) { // Extended timestamp: 0 or 4 bytes // This field MUST be sent when the normal timsestamp is set to // 0xffffff, it MUST NOT be sent if the normal timestamp is set to // anything else. So for values less than 0xffffff the normal // timestamp field SHOULD be used in which case the extended timestamp // MUST NOT be present. For values greater than or equal to 0xffffff // the normal timestamp field MUST NOT be used and MUST be set to // 0xffffff and the extended timestamp MUST be sent. // // if extended timestamp, the timestamp must >= RTMP_EXTENDED_TIMESTAMP // we set the timestamp to RTMP_EXTENDED_TIMESTAMP to identify we // got an extended timestamp. chunk->header.timestamp = RTMP_EXTENDED_TIMESTAMP; } else { if (fmt == RTMP_FMT_TYPE0) { // 6.1.2.1. Type 0 // For a type-0 chunk, the absolute timestamp of the message is sent // here. chunk->header.timestamp = chunk->header.timestamp_delta; } else { // 6.1.2.2. Type 1 // 6.1.2.3. Type 2 // For a type-1 or type-2 chunk, the difference between the previous // chunk's timestamp and the current chunk's timestamp is sent here. chunk->header.timestamp += chunk->header.timestamp_delta; } } if (fmt <= RTMP_FMT_TYPE1) { pp = (char*)&chunk->header.payload_length; pp[2] = *p++; pp[1] = *p++; pp[0] = *p++; pp[3] = 0; // if msg exists in cache, the size must not changed. if (chunk->msg->size > 0 && chunk->msg->size != chunk->header.payload_length) { ret = ERROR_RTMP_PACKET_SIZE; srs_error("msg exists in chunk cache, " "size=%d cannot change to %d, ret=%d", chunk->msg->size, chunk->header.payload_length, ret); return ret; } chunk->header.message_type = *p++; if (fmt == RTMP_FMT_TYPE0) { pp = (char*)&chunk->header.stream_id; pp[0] = *p++; pp[1] = *p++; pp[2] = *p++; pp[3] = *p++; srs_verbose("header read completed. fmt=%d, mh_size=%d, ext_time=%d, time=%"PRId64", payload=%d, type=%d, sid=%d", fmt, mh_size, chunk->extended_timestamp, chunk->header.timestamp, chunk->header.payload_length, chunk->header.message_type, chunk->header.stream_id); } else { srs_verbose("header read completed. fmt=%d, mh_size=%d, ext_time=%d, time=%"PRId64", payload=%d, type=%d", fmt, mh_size, chunk->extended_timestamp, chunk->header.timestamp, chunk->header.payload_length, chunk->header.message_type); } } else { srs_verbose("header read completed. fmt=%d, mh_size=%d, ext_time=%d, time=%"PRId64"", fmt, mh_size, chunk->extended_timestamp, chunk->header.timestamp); } } else { // update the timestamp even fmt=3 for first stream if (is_fresh_packet && !chunk->extended_timestamp) { chunk->header.timestamp += chunk->header.timestamp_delta; } srs_verbose("header read completed. fmt=%d, size=%d, ext_time=%d", fmt, mh_size, chunk->extended_timestamp); } if (chunk->extended_timestamp) { mh_size += 4; required_size = bh_size + mh_size; srs_verbose("read header ext time. fmt=%d, ext_time=%d, mh_size=%d", fmt, chunk->extended_timestamp, mh_size); if ((ret = buffer->ensure_buffer_bytes(skt, required_size)) != ERROR_SUCCESS) { if (ret != ERROR_SOCKET_TIMEOUT) { srs_error("read %dbytes message header failed. required_size=%d, ret=%d", mh_size, required_size, ret); } return ret; } // ffmpeg/librtmp may donot send this filed, need to detect the value. // @see also: http://blog.csdn.net/win_lin/article/details/13363699 u_int32_t timestamp = 0x00; char* pp = (char*)×tamp; pp[3] = *p++; pp[2] = *p++; pp[1] = *p++; pp[0] = *p++; // compare to the chunk timestamp, which is set by chunk message header // type 0,1 or 2. u_int32_t chunk_timestamp = chunk->header.timestamp; if (chunk_timestamp > RTMP_EXTENDED_TIMESTAMP && chunk_timestamp != timestamp) { mh_size -= 4; srs_verbose("ignore the 4bytes extended timestamp. mh_size=%d", mh_size); } else { chunk->header.timestamp = timestamp; } srs_verbose("header read ext_time completed. time=%"PRId64"", chunk->header.timestamp); } // valid message if (chunk->header.payload_length < 0) { ret = ERROR_RTMP_MSG_INVLIAD_SIZE; srs_error("RTMP message size must not be negative. size=%d, ret=%d", chunk->header.payload_length, ret); return ret; } // copy header to msg chunk->msg->header = chunk->header; // increase the msg count, the chunk stream can accept fmt=1/2/3 message now. chunk->msg_count++; return ret;}
GO代码如下:
func (r *RtmpProtocol) read_message_header(chunk *RtmpChunkStream, format byte) (mh_size int, err error) { /** * we should not assert anything about fmt, for the first packet. * (when first packet, the chunk->msg is NULL). * the fmt maybe 0/1/2/3, the FMLE will send a 0xC4 for some audio packet. * the previous packet is: * 04 // fmt=0, cid=4 * 00 00 1a // timestamp=26 *00 00 9d // payload_length=157 * 08 // message_type=8(audio) * 01 00 00 00 // stream_id=1 * the current packet maybe: * c4 // fmt=3, cid=4 * it's ok, for the packet is audio, and timestamp delta is 26. * the current packet must be parsed as: * fmt=0, cid=4 * timestamp=26+26=52 * payload_length=157 * message_type=8(audio) * stream_id=1 * so we must update the timestamp even fmt=3 for first packet. */ // fresh packet used to update the timestamp even fmt=3 for first packet. is_fresh_packet := false if chunk.Msg == nil { is_fresh_packet = true } // but, we can ensure that when a chunk stream is fresh, // the fmt must be 0, a new stream. if chunk.MsgCount == 0 && format != RTMP_FMT_TYPE0 { err = RtmpError{code:ERROR_RTMP_CHUNK_START, desc:"protocol error, fmt of first chunk must be 0"} return } // when exists cache msg, means got an partial message, // the fmt must not be type0 which means new message. if chunk.Msg != nil && format == RTMP_FMT_TYPE0 { err = RtmpError{code:ERROR_RTMP_CHUNK_START, desc:"protocol error, unexpect start of new chunk"} return } // create msg when new chunk stream start if chunk.Msg == nil { chunk.Msg = new(RtmpMessage) } // read message header from socket to buffer. mh_sizes := []int{11, 7, 3, 0} mh_size = mh_sizes[int(format)]; if err = r.buffer.ensure_buffer_bytes(mh_size); err != nil { return } // parse the message header. // see also: ngx_rtmp_recv if format <= RTMP_FMT_TYPE2 { chunk.Header.TimestampDelta = r.buffer.ReadUInt24() // fmt: 0 // timestamp: 3 bytes // If the timestamp is greater than or equal to 16777215 // (hexadecimal 0x00ffffff), this value MUST be 16777215, and the // ‘extended timestamp header’ MUST be present. Otherwise, this value // SHOULD be the entire timestamp. // // fmt: 1 or 2 // timestamp delta: 3 bytes // If the delta is greater than or equal to 16777215 (hexadecimal // 0x00ffffff), this value MUST be 16777215, and the ‘extended // timestamp header’ MUST be present. Otherwise, this value SHOULD be // the entire delta. if chunk.ExtendedTimestamp = false; chunk.Header.TimestampDelta >= RTMP_EXTENDED_TIMESTAMP { chunk.ExtendedTimestamp = true } if chunk.ExtendedTimestamp { // Extended timestamp: 0 or 4 bytes // This field MUST be sent when the normal timsestamp is set to // 0xffffff, it MUST NOT be sent if the normal timestamp is set to // anything else. So for values less than 0xffffff the normal // timestamp field SHOULD be used in which case the extended timestamp // MUST NOT be present. For values greater than or equal to 0xffffff // the normal timestamp field MUST NOT be used and MUST be set to // 0xffffff and the extended timestamp MUST be sent. // // if extended timestamp, the timestamp must >= RTMP_EXTENDED_TIMESTAMP // we set the timestamp to RTMP_EXTENDED_TIMESTAMP to identify we // got an extended timestamp. chunk.Header.Timestamp = RTMP_EXTENDED_TIMESTAMP } else { if format == RTMP_FMT_TYPE0 { // 6.1.2.1. Type 0 // For a type-0 chunk, the absolute timestamp of the message is sent // here. chunk.Header.Timestamp = uint64(chunk.Header.TimestampDelta) } else { // 6.1.2.2. Type 1 // 6.1.2.3. Type 2 // For a type-1 or type-2 chunk, the difference between the previous // chunk's timestamp and the current chunk's timestamp is sent here. chunk.Header.Timestamp += uint64(chunk.Header.TimestampDelta) } } if format <= RTMP_FMT_TYPE1 { chunk.Header.PayloadLength = r.buffer.ReadUInt24() // if msg exists in cache, the size must not changed. if chunk.Msg.payload != nil && len(chunk.Msg.payload) != int(chunk.Header.PayloadLength) { err = RtmpError{code:ERROR_RTMP_PACKET_SIZE, desc:"cached message size should never change"} return } chunk.Header.MessageType = r.buffer.ReadByte() if format == RTMP_FMT_TYPE0 { chunk.Header.StreamId = r.buffer.ReadUInt32Le() } } } else { // update the timestamp even fmt=3 for first stream if is_fresh_packet && !chunk.ExtendedTimestamp { chunk.Header.Timestamp += uint64(chunk.Header.TimestampDelta) } } if chunk.ExtendedTimestamp { mh_size += 4 if err = r.buffer.ensure_buffer_bytes(4); err != nil { return } // ffmpeg/librtmp may donot send this filed, need to detect the value. // @see also: http://blog.csdn.net/win_lin/article/details/13363699 timestamp := r.buffer.ReadUInt32() // compare to the chunk timestamp, which is set by chunk message header // type 0,1 or 2. if chunk.Header.Timestamp > RTMP_EXTENDED_TIMESTAMP && chunk.Header.Timestamp != uint64(timestamp) { mh_size -= 4 r.buffer.Next(-4) } else { chunk.Header.Timestamp = uint64(timestamp) } } // valid message if int32(chunk.Header.PayloadLength) < 0 { err = RtmpError{code:ERROR_RTMP_MSG_INVLIAD_SIZE, desc:"chunk packet should never be negative"} return } // copy header to msg copy := *chunk.Header chunk.Msg.Header = © // increase the msg count, the chunk stream can accept fmt=1/2/3 message now. chunk.MsgCount++ return}
调试起来也差不多。不过C++的SRS用到了st,调试协程是比较麻烦。
0 0
- GO和C++代码对比,GO少个25%代码
- go语言和C语言的对比
- 《Go语言编程》[4.4 并发通信]代码thread.c和thread.go错误
- Go调用C代码,Cgo札记
- go语言代码测试
- 怎样编写Go代码
- Go 代码审查建议
- go代理服务器代码
- python调用Go代码
- go代码片段
- Go:如何组织代码
- go聊天代码
- Go 代码风格
- Go入门:怎样编写Go代码
- GO中调用C代码(CGO)中的坑
- 《go语言编程》音乐库代码
- 用go代码操作git
- Go语言获取环境变量代码
- jlink烧写mini2440 nor flash
- soft排序
- druid介绍
- $250000投资的陷阱(转自创业孵化器Year One Labs的联合创始人Ben Yoskovitz)
- java学习笔记<八>final修饰符
- GO和C++代码对比,GO少个25%代码
- 山理工acm各位数相加
- 第三周:接口
- 网络编程(7)字节序对跨平台数据传输的影响
- JAVA读写资源文件
- NVelocity介绍
- JAVA UUID 生成
- Rust运行时指南(官方文档翻译)
- 冒泡排序