From 765db1eb8b1cbfbd7fc7426e86a92129727a6cbc Mon Sep 17 00:00:00 2001 From: xia-chu <771730766@qq.com> Date: Wed, 14 Apr 2021 16:19:46 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0rtcp=20fci=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Rtcp/RtcpFCI.cpp | 128 ++++++++++++++++++++++++++++++++++++++++ src/Rtcp/RtcpFCI.h | 107 ++++++++++++++++++++++----------- tests/test_rtcp_fci.cpp | 41 +++++++++++++ 3 files changed, 243 insertions(+), 33 deletions(-) create mode 100644 tests/test_rtcp_fci.cpp diff --git a/src/Rtcp/RtcpFCI.cpp b/src/Rtcp/RtcpFCI.cpp index 60faf0ab..d03d1a60 100644 --- a/src/Rtcp/RtcpFCI.cpp +++ b/src/Rtcp/RtcpFCI.cpp @@ -9,9 +9,137 @@ */ +#include "assert.h" #include "RtcpFCI.h" +#define CHECK(exp) Assert_Throw(!(exp), #exp, __FUNCTION__, __FILE__, __LINE__); namespace mediakit { +FCI_SLI::FCI_SLI(uint16_t first, uint16_t number, uint8_t pic_id) { + //13 bits + first &= 0x1FFF; + //13 bits + number &= 0x1FFF; + //6 bits + pic_id &= 0x3F; + data = (first << 19) | (number << 6) | pic_id; + data = htonl(data); +} + +uint16_t FCI_SLI::getFirst() const { + return data >> 19; +} + +uint16_t FCI_SLI::getNumber() const { + return (data >> 6) & 0x1FFF; +} + +uint8_t FCI_SLI::getPicID() const { + return data & 0x3F; +} + +void FCI_SLI::net2Host() { + data = ntohl(data); +} + +string FCI_SLI::dumpString() const { + return StrPrinter << "First:" << getFirst() << ", Number:" << getNumber() << ", PictureID:" << (int)getPicID(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void FCI_FIR::net2Host() { + ssrc = ntohl(ssrc); + reserved = ntohl(reserved) >> 8; +} + +string FCI_FIR::dumpString() const { + return StrPrinter << "ssrc:" << ssrc << ", seq_number:" << seq_number << ", reserved:" << reserved; +} + +FCI_FIR::FCI_FIR(uint32_t ssrc, uint8_t seq_number, uint32_t reserved) { + this->ssrc = htonl(ssrc); + this->seq_number = seq_number; + this->reserved = htonl(reserved) >> 8; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +string FCI_REMB::create(const initializer_list &ssrcs, uint32_t bitrate) { + CHECK(ssrcs.size() > 0 && ssrcs.size() <= 0xFF); + string ret; + ret.resize(kSize + ssrcs.size() * 4); + FCI_REMB *thiz = (FCI_REMB *) ret.data(); + memcpy(thiz->magic, "REMB", 4); + + /* bitrate --> BR Exp/BR Mantissa */ + uint8_t b = 0; + uint8_t exp = 0; + uint32_t mantissa = 0; + for (b = 0; b < 32; b++) { + if (bitrate <= ((uint32_t) 0x3FFFF << b)) { + exp = b; + break; + } + } + if (b > 31) { + b = 31; + } + mantissa = bitrate >> b; + //Num SSRC (8 bits) + thiz->bitrate[0] = ssrcs.size() & 0xFF; + //BR Exp (6 bits)/BR Mantissa (18 bits) + thiz->bitrate[1] = (uint8_t) ((exp << 2) + ((mantissa >> 16) & 0x03)); + //BR Mantissa (18 bits) + thiz->bitrate[2] = (uint8_t) (mantissa >> 8); + //BR Mantissa (18 bits) + thiz->bitrate[3] = (uint8_t) (mantissa); + + //设置ssrc列表 + auto ptr = thiz->ssrc_feedback; + for (auto &ssrc : ssrcs) { + *(ptr++) = htonl(ssrc); + } + return ret; +} + +void FCI_REMB::net2Host(size_t total_size) { + CHECK(total_size >= kSize); + CHECK(memcmp(magic, "REMB", 4) == 0); + auto num_ssrc = bitrate[0]; + auto expect_size = kSize + 4 * num_ssrc; + CHECK(total_size == expect_size); + auto ptr = ssrc_feedback; + while (num_ssrc--) { + *(ptr++) = ntohl(*ptr); + } +} + +uint32_t FCI_REMB::getBitRate() const { + uint8_t exp = (bitrate[1] >> 2) & 0x3F; + uint32_t mantissa = (bitrate[1] & 0x03) << 16; + mantissa += (bitrate[2] << 8); + mantissa += (bitrate[3]); + return mantissa << exp; +} + +vector FCI_REMB::getSSRC() { + vector ret; + auto num_ssrc = bitrate[0]; + auto ptr = ssrc_feedback; + while (num_ssrc--) { + ret.emplace_back(ptr++); + } + return ret; +} + +string FCI_REMB::dumpString() const { + _StrPrinter printer; + printer << "bitrate:" << getBitRate() << ", ssrc:"; + for (auto &ssrc : ((FCI_REMB *) this)->getSSRC()) { + printer << *ssrc << " "; + } + return printer; +} }//namespace mediakit \ No newline at end of file diff --git a/src/Rtcp/RtcpFCI.h b/src/Rtcp/RtcpFCI.h index adb4abf3..f36056d9 100644 --- a/src/Rtcp/RtcpFCI.h +++ b/src/Rtcp/RtcpFCI.h @@ -24,11 +24,36 @@ namespace mediakit { // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | First | Number | PictureID | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +//First: 13 bits +// The macroblock (MB) address of the first lost macroblock. The MB +// numbering is done such that the macroblock in the upper left +// corner of the picture is considered macroblock number 1 and the +// number for each macroblock increases from left to right and then +// from top to bottom in raster-scan order (such that if there is a +// total of N macroblocks in a picture, the bottom right macroblock +// is considered macroblock number N). +// +// Number: 13 bits +// The number of lost macroblocks, in scan order as discussed above. +// +// PictureID: 6 bits +// The six least significant bits of the codec-specific identifier +// that is used to reference the picture in which the loss of the +// macroblock(s) has occurred. For many video codecs, the PictureID +// is identical to the Temporal Reference. class FCI_SLI { public: - uint32_t first : 13; - uint32_t number : 13; - uint32_t pic_id : 6; + static size_t constexpr kSize = 4; + + FCI_SLI(uint16_t first, uint16_t number, uint8_t pic_id); + uint16_t getFirst() const; + uint16_t getNumber() const; + uint8_t getPicID() const; + void net2Host(); + string dumpString() const; + +private: + uint32_t data; } PACKED; //PSFB fmt = 3 @@ -61,12 +86,15 @@ public: // Native RPSI bit string: variable length // The RPSI information as natively defined by the video codec. - char str[1]; + char bit_string[5]; //Padding: #PB bits // A number of bits set to zero to fill up the contents of the RPSI // message to the next 32-bit boundary. The number of padding bits // MUST be indicated by the PB field. + uint8_t padding; + + static size_t constexpr kSize = 8; } PACKED; //PSFB fmt = 4 @@ -79,6 +107,15 @@ public: // | Seq nr. | Reserved | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ class FCI_FIR { +public: + uint32_t ssrc; + uint32_t seq_number: 8; + uint32_t reserved: 24; + + static size_t constexpr kSize = 8; + FCI_FIR(uint32_t ssrc, uint8_t seq_number, uint32_t reserved = 0); + void net2Host(); + string dumpString() const; } PACKED; @@ -92,7 +129,8 @@ class FCI_FIR { // | Seq nr. | Reserved | Index | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ class FCI_TSTR { - +public: + static size_t constexpr kSize = 8; } PACKED; //PSFB fmt = 6 @@ -104,7 +142,7 @@ class FCI_TSTR { // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | Seq nr. | Reserved | Index | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -class FCI_TSTN { +class FCI_TSTN : public FCI_TSTR{ } PACKED; @@ -120,7 +158,8 @@ class FCI_TSTN { // | VBCM Octet String.... | Padding | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ class FCI_VBCM { - +public: + static size_t constexpr kSize = 12; } PACKED; //PSFB fmt = 15 @@ -128,12 +167,6 @@ class FCI_VBCM { // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// |V=2|P| FMT=15 | PT=206 | length | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | SSRC of packet sender | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | SSRC of media source | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | Unique identifier 'R' 'E' 'M' 'B' | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | Num SSRC | BR Exp | BR Mantissa | @@ -141,31 +174,39 @@ class FCI_VBCM { // | SSRC feedback | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ... | +// Num SSRC (8 bits): Number of SSRCs in this message. +// +// BR Exp (6 bits): The exponential scaling of the mantissa for the +// maximum total media bit rate value, ignoring all packet +// overhead. The value is an unsigned integer [0..63], as +// in RFC 5104 section 4.2.2.1. +// +// BR Mantissa (18 bits): The mantissa of the maximum total media bit +// rate (ignoring all packet overhead) that the sender of +// the REMB estimates. The BR is the estimate of the +// traveled path for the SSRCs reported in this message. +// The value is an unsigned integer in number of bits per +// second. +// +// SSRC feedback (32 bits) Consists of one or more SSRC entries which +// this feedback message applies to. class FCI_REMB { public: + static size_t constexpr kSize = 8; + + static string create(const std::initializer_list &ssrcs, uint32_t bitrate); + void net2Host(size_t total_size); + string dumpString() const; + uint32_t getBitRate() const; + vector getSSRC(); + //Unique identifier 'R' 'E' 'M' 'B' char magic[4]; - - //Number of SSRCs in this message. - uint32_t num_ssrc : 8; - - // BR Exp (6 bits): The exponential scaling of the mantissa for the - // maximum total media bit rate value, ignoring all packet - // overhead. The value is an unsigned integer [0..63], as - // in RFC 5104 section 4.2.2.1. - uint32_t br_exp : 6; - - //BR Mantissa (18 bits): The mantissa of the maximum total media bit - // rate (ignoring all packet overhead) that the sender of - // the REMB estimates. The BR is the estimate of the - // traveled path for the SSRCs reported in this message. - // The value is an unsigned integer in number of bits per - // second. - uint32_t br_mantissa : 18; - + //Num SSRC (8 bits)/BR Exp (6 bits)/ BR Mantissa (18 bits) + uint8_t bitrate[4]; // SSRC feedback (32 bits) Consists of one or more SSRC entries which // this feedback message applies to. - uint32_t ssrc_feedback; + uint32_t ssrc_feedback[1]; } PACKED; @@ -254,7 +295,7 @@ public: // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | recv delta | recv delta | zero padding | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -class FCI_TWCC : public FCI_TMMBR{ +class FCI_TWCC{ public: } PACKED; diff --git a/tests/test_rtcp_fci.cpp b/tests/test_rtcp_fci.cpp new file mode 100644 index 00000000..c974d4b0 --- /dev/null +++ b/tests/test_rtcp_fci.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved. + * + * This file is part of ZLToolKit(https://github.com/xia-chu/ZLToolKit). + * + * Use of this source code is governed by MIT license that can be found in the + * LICENSE file in the root of the source tree. All contributing project authors + * may be found in the AUTHORS file in the root of the source tree. + */ + +#include +#include "Util/logger.h" +#include "Rtcp/RtcpFCI.h" +using namespace std; +using namespace toolkit; +using namespace mediakit; + +int main() { + //初始化日志系统 + Logger::Instance().add(std::make_shared ()); + + { + FCI_SLI fci(0xFFFF, 0, 0xFF); + InfoL << 0b10101010101 << " " << 0b01010101010 << " " << (int) 0b101010 << " " << hexdump(&fci, FCI_SLI::kSize); + fci.net2Host(); + InfoL << fci.dumpString(); + } + { + FCI_FIR fci(123456, 139, 456789); + InfoL << hexdump(&fci, FCI_FIR::kSize); + fci.net2Host(); + InfoL << fci.dumpString(); + } + { + auto str = FCI_REMB::create({1234,2345,5678}, 4 * 1024 * 1024); + FCI_REMB *ptr = (FCI_REMB *)str.data(); + ptr->net2Host(str.size()); + InfoL << ptr->dumpString(); + } + return 0; +}