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
原创粉丝点击