1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

Protobuf: Extract protobuf encoder.

This commit is contained in:
winlin 2022-08-26 18:46:26 +08:00
parent a54d371549
commit 8bc7342c3c
6 changed files with 611 additions and 221 deletions

View file

@ -0,0 +1,210 @@
//
// Copyright (c) 2013-2022 The SRS Authors
//
// SPDX-License-Identifier: MIT or MulanPSL-2.0
//
#include <srs_protocol_protobuf.hpp>
#include <srs_kernel_error.hpp>
#include <srs_kernel_buffer.hpp>
using namespace std;
// See Go bits.Len64 of package math/bits.
int SrsProtobufVarints::bits_len64(uint64_t x)
{
// See Go bits.len8tab of package math/bits.
static uint8_t bits_len8tab[256] = {
0x00, 0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
};
int n = 0;
if (x >= (uint64_t)1<<32) {
x >>= 32;
n = 32;
}
if (x >= (uint64_t)1<<16) {
x >>= 16;
n += 16;
}
if (x >= (uint64_t)1<<8) {
x >>= 8;
n += 8;
}
return n + int(bits_len8tab[x]);
}
// See Go protowire.SizeVarint of package google.golang.org/protobuf/encoding/protowire
int SrsProtobufVarints::sizeof_varint(uint64_t v)
{
int n = bits_len64(v);
return int(9 * uint32_t(n) + 64) / 64;
}
// See Go protowire.AppendVarint of package google.golang.org/protobuf/encoding/protowire
srs_error_t SrsProtobufVarints::encode(SrsBuffer* b, uint64_t v)
{
srs_error_t err = srs_success;
if (!b->require(SrsProtobufVarints::sizeof_varint(v))) {
return srs_error_new(ERROR_PB_NO_SPACE, "require %d only %d bytes", v, b->left());
}
if (v < (uint64_t)1<<7) {
b->write_1bytes((uint8_t)v);
} else if (v < (uint64_t)1<<14) {
b->write_1bytes((uint8_t)(((v>>0)&0x7f)|0x80));
b->write_1bytes((uint8_t)(v>>7));
} else if (v < (uint64_t)1<<21) {
b->write_1bytes((uint8_t)(((v>>0)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>7)&0x7f)|0x80));
b->write_1bytes((uint8_t)(v>>14));
} else if (v < (uint64_t)1<<28) {
b->write_1bytes((uint8_t)(((v>>0)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>7)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>14)&0x7f)|0x80));
b->write_1bytes((uint8_t)(v>>21));
} else if (v < (uint64_t)1<<35) {
b->write_1bytes((uint8_t)(((v>>0)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>7)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>14)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>21)&0x7f)|0x80));
b->write_1bytes((uint8_t)(v>>28));
} else if (v < (uint64_t)1<<42) {
b->write_1bytes((uint8_t)(((v>>0)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>7)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>14)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>21)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>28)&0x7f)|0x80));
b->write_1bytes((uint8_t)(v>>35));
} else if (v < (uint64_t)1<<49) {
b->write_1bytes((uint8_t)(((v>>0)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>7)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>14)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>21)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>28)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>35)&0x7f)|0x80));
b->write_1bytes((uint8_t)(v>>42));
} else if(v < (uint64_t)1<<56) {
b->write_1bytes((uint8_t)(((v>>0)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>7)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>14)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>21)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>28)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>35)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>42)&0x7f)|0x80));
b->write_1bytes((uint8_t)(v>>49));
} else if (v < (uint64_t)1<<63) {
b->write_1bytes((uint8_t)(((v>>0)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>7)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>14)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>21)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>28)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>35)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>42)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>49)&0x7f)|0x80));
b->write_1bytes((uint8_t)(v>>56));
} else {
b->write_1bytes((uint8_t)(((v>>0)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>7)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>14)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>21)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>28)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>35)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>42)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>49)&0x7f)|0x80));
b->write_1bytes((uint8_t)(((v>>56)&0x7f)|0x80));
b->write_1bytes((uint8_t)1);
}
return err;
}
// See Go protowire.SizeBytes of package google.golang.org/protobuf/encoding/protowire
int SrsProtobufString::sizeof_string(const std::string& v)
{
uint64_t n = v.length();
return SrsProtobufVarints::sizeof_varint(uint64_t(n)) + n;
}
// See Go protowire.AppendString of package google.golang.org/protobuf/encoding/protowire
srs_error_t SrsProtobufString::encode(SrsBuffer* b, const std::string& v)
{
srs_error_t err = srs_success;
uint64_t n = v.length();
if ((err = SrsProtobufVarints::encode(b, n)) != srs_success) {
return srs_error_wrap(err, "string size %d", n);
}
// Ignore content if empty.
if (v.empty()) {
return err;
}
if (!b->require(n)) {
return srs_error_new(ERROR_PB_NO_SPACE, "require %d only %d byte", n, b->left());
}
b->write_string(v);
return err;
}
int SrsProtobufObject::sizeof_object(ISrsEncoder* obj)
{
uint64_t size = obj->nb_bytes();
return SrsProtobufVarints::sizeof_varint(size) + size;
}
srs_error_t SrsProtobufObject::encode(SrsBuffer* b, ISrsEncoder* obj)
{
srs_error_t err = srs_success;
// Encode the varint size of children.
uint64_t size = obj->nb_bytes();
if ((err = SrsProtobufVarints::encode(b, size)) != srs_success) {
return srs_error_wrap(err, "encode size=%d", (int)size);
}
// Encode the log group itself.
if ((err = obj->encode(b)) != srs_success) {
return srs_error_wrap(err, "encode group");
}
return err;
}
int SrsProtobufKey::sizeof_key()
{
return 1;
}
srs_error_t SrsProtobufKey::encode(SrsBuffer* b, uint8_t fieldId, SrsProtobufField fieldType)
{
srs_error_t err = srs_success;
if (!b->require(1)) {
return srs_error_new(ERROR_PB_NO_SPACE, "require 1 byte");
}
uint8_t v = (fieldId << 3) | uint8_t(fieldType);
b->write_1bytes(v);
return err;
}

View file

@ -0,0 +1,107 @@
//
// Copyright (c) 2013-2022 The SRS Authors
//
// SPDX-License-Identifier: MIT or MulanPSL-2.0
//
#ifndef SRS_PROTOCOL_PROTOBUF_HPP
#define SRS_PROTOCOL_PROTOBUF_HPP
#include <srs_core.hpp>
#include <string>
class SrsBuffer;
class ISrsEncoder;
// See https://developers.google.com/protocol-buffers/docs/encoding#varints
class SrsProtobufVarints
{
private:
static int bits_len64(uint64_t x);
public:
static int sizeof_varint(uint64_t v);
static srs_error_t encode(SrsBuffer* b, uint64_t v);
};
// See https://developers.google.com/protocol-buffers/docs/encoding#strings
class SrsProtobufString
{
public:
static int sizeof_string(const std::string& v);
static srs_error_t encode(SrsBuffer* b, const std::string& v);
};
// For embeded messages and packed repeated fields, see usage of SrsProtobufKey.
class SrsProtobufObject
{
public:
static int sizeof_object(ISrsEncoder* obj);
static srs_error_t encode(SrsBuffer* b, ISrsEncoder* obj);
};
// See https://developers.google.com/protocol-buffers/docs/encoding#structure
enum SrsProtobufField
{
// For int32, int64, uint32, uint64, sint32, sint64, bool, enum
SrsProtobufFieldVarint = 0,
// For fixed64, sfixed64, double
SrsProtobufField64bit = 1,
// For string, bytes, embedded messages, packed repeated fields
SrsProtobufFieldString = 2,
SrsProtobufFieldBytes = 2,
SrsProtobufFieldObject = 2,
SrsProtobufFieldLengthDelimited = 2,
// For fixed32, sfixed32, float
SrsProtobufField32bit = 5,
};
// See https://developers.google.com/protocol-buffers/docs/encoding#structure
// See https://cloud.tencent.com/document/api/614/16873
//
////////////////////////////////////////////////////////////////////////////////
// If key is string, for example:
// message Content {
// required string value = 2;
// }
// We can get the size of value:
// SrsProtobufKey::sizeof_key() + SrsProtobufString::sizeof_string(value_)
// And marshal as:
// SrsProtobufKey::encode(b, 2, SrsProtobufFieldString)
// SrsProtobufString::encode(b, value_)
//
////////////////////////////////////////////////////////////////////////////////
// If key is varints, for example:
// message Log {
// required int64 time = 1;
// }
// We can get the size of logs:
// SrsProtobufKey::sizeof_key() + SrsProtobufVarints::sizeof_varint(time_)
// And marshal as:
// SrsProtobufKey::encode(b, 1, SrsProtobufFieldVarint)
// SrsProtobufVarints::encode(b, time_)
//
////////////////////////////////////////////////////////////////////////////////
// If key is object(or embeded message, or packed repeated fields), for example:
// message LogGroupList {
// repeated LogGroup logGroupList = 1;
// }
// We can get the size of logs:
// for group in vector<LogGroup*>:
// size += SrsProtobufKey::sizeof_key() + SrsProtobufObject::sizeof_object(group)
// And marshal as:
// for group in vector<LogGroup*>:
// SrsProtobufKey::encode(b, 1, SrsProtobufFieldLengthDelimited)
// SrsProtobufObject::encode(b, group)
// Note that there is always a key and length for each repeat object.
class SrsProtobufKey
{
public:
static int sizeof_key();
// Each key in the streamed message is a varint with the value (field_number << 3) | wire_type in other words,
// the last three bits of the number store the wire type.
static srs_error_t encode(SrsBuffer* b, uint8_t fieldId, SrsProtobufField fieldType);
};
#endif