基本完成twcc rtcp fci的生成

This commit is contained in:
xiongziliang 2021-10-07 12:28:59 +08:00
parent e02bc9ce67
commit 0ae1d46892
4 changed files with 109 additions and 90 deletions

View File

@ -285,22 +285,16 @@ public:
//获取symbollist //获取symbollist
vector<SymbolStatus> getSymbolList() const; vector<SymbolStatus> getSymbolList() const;
//构造函数 //构造函数
StatusVecChunk(const vector<SymbolStatus> &status); StatusVecChunk(bool symbol_bit, const vector<SymbolStatus> &status);
//打印本对象 //打印本对象
string dumpString() const; string dumpString() const;
} PACKED; } PACKED;
StatusVecChunk::StatusVecChunk(const vector<SymbolStatus> &status) { StatusVecChunk::StatusVecChunk(bool symbol_bit, const vector<SymbolStatus> &status) {
CHECK((1 + symbol_bit) * status.size() <= 14);
uint16_t value = 0; uint16_t value = 0;
type = 1; type = 1;
if (status.size() == 14) { symbol = symbol_bit;
symbol = 0;
} else if (status.size() == 7) {
symbol = 1;
} else {
//非法
CHECK(0);
}
int i = 13; int i = 13;
for (auto &item : status) { for (auto &item : status) {
CHECK(item <= SymbolStatus::reserved); CHECK(item <= SymbolStatus::reserved);
@ -428,8 +422,8 @@ static int16_t getRecvDelta(SymbolStatus status, uint8_t *&ptr, const uint8_t *e
return delta; return delta;
} }
map<uint16_t, std::pair<SymbolStatus, int16_t/*stamp*/> > FCI_TWCC::getPacketChunkList(size_t total_size) const { FCI_TWCC::TwccPacketStatus FCI_TWCC::getPacketChunkList(size_t total_size) const {
map<uint16_t, std::pair<SymbolStatus, int16_t> > ret; TwccPacketStatus ret;
auto ptr = (uint8_t *) this + kSize; auto ptr = (uint8_t *) this + kSize;
auto end = (uint8_t *) this + total_size; auto end = (uint8_t *) this + total_size;
CHECK(ptr < end); CHECK(ptr < end);
@ -475,48 +469,83 @@ string FCI_TWCC::dumpString(size_t total_size) const {
return std::move(printer); return std::move(printer);
} }
static void appendDeltaString(string &delta_str, FCI_TWCC::TwccPacketStatus &status, int count){
for (auto it = status.begin(); it != status.end() && count--;) {
switch (it->second.first) {
//large delta模式先写高字节再写低字节
case SymbolStatus::large_delta: delta_str.push_back((it->second.second >> 8) & 0xFF);
//small delta模式只写低字节
case SymbolStatus::small_delta: delta_str.push_back(it->second.second & 0xFF); break;
default: break;
}
//移除已经处理过的数据
it = status.erase(it);
}
}
string FCI_TWCC::create(uint32_t ref_time, uint8_t fb_pkt_count, TwccPacketStatus &status) {
string fci;
fci.resize(FCI_TWCC::kSize);
FCI_TWCC *ptr = (FCI_TWCC *) (fci.data());
ptr->base_seq = htons(status.begin()->first);
ptr->pkt_status_count = htons(status.size());
ptr->fb_pkt_count = fb_pkt_count;
ptr->ref_time[0] = (ref_time >> 16) & 0xFF;
ptr->ref_time[1] = (ref_time >> 8) & 0xFF;
ptr->ref_time[2] = (ref_time >> 0) & 0xFF;
string delta_str;
while (!status.empty()) {
{
//第一个rtp的状态
auto symbol = status.begin()->second.first;
int16_t count = 0;
for (auto &pr : status) {
if (++count == (0xFFFF >> 3)) {
//RunLengthChunk 13个bit表明rtp个数最多可以表述0xFFFF >> 3个rtp状态
break;
}
if (pr.second.first != symbol) {
//状态发送变更了本chunk结束
break;
}
}
if (count >= 7) {
//连续状态相同个数大于6个时使用RunLengthChunk模式比较节省带宽
RunLengthChunk chunk(symbol, count);
fci.append((char *)&chunk, RunLengthChunk::kSize);
appendDeltaString(delta_str, status, count);
continue;
}
}
{
//StatusVecChunk模式
//symbol_list中元素是1个bit
auto symbol = 0;
int count = 0;
vector<SymbolStatus> vec;
for (auto &pr : status) {
vec.push_back(pr.second.first);
if (pr.second.first >= SymbolStatus::large_delta) {
//symbol_list中元素是2个bit
symbol = 1;
}
if ((1 + symbol) * (++count) == 14) {
//symbol为0时最多存放14个rtp的状态
//symbol为1时最多存放7个rtp的状态
break;
}
}
StatusVecChunk chunk(symbol, vec);
fci.append((char *)&chunk, StatusVecChunk::kSize);
appendDeltaString(delta_str, status, count);
}
}
//recv delta部分
fci.append(delta_str);
return fci;
}
}//namespace mediakit }//namespace mediakit
#if 1
using namespace mediakit;
void testFCI() {
{
FCI_SLI fci(8191, 0, 63);
InfoL << hexdump(&fci, FCI_SLI::kSize) << fci.dumpString();
}
{
FCI_FIR fci(123456, 139, 456789);
InfoL << hexdump(&fci, FCI_FIR::kSize) << fci.dumpString();
}
{
auto str = FCI_REMB::create({1234, 2345, 5678}, 4 * 1024 * 1024);
FCI_REMB *ptr = (FCI_REMB *) str.data();
InfoL << hexdump(str.data(), str.size()) << ptr->dumpString();
}
{
FCI_NACK nack(1234, vector<bool>({1, 0, 0, 0, 1, 0, 1, 0, 1, 0}));
InfoL << hexdump(&nack, FCI_NACK::kSize) << nack.dumpString();
}
{
RunLengthChunk chunk(SymbolStatus::large_delta, 8024);
InfoL << hexdump(&chunk, RunLengthChunk::kSize) << chunk.dumpString();
}
auto lam = [](const initializer_list<int> &lst) {
vector<SymbolStatus> ret;
for (auto &num : lst) {
ret.emplace_back((SymbolStatus) num);
}
return ret;
};
{
StatusVecChunk chunk(lam({0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1}));
InfoL << hexdump(&chunk, StatusVecChunk::kSize) << chunk.dumpString();
}
{
StatusVecChunk chunk(lam({0, 1, 2, 2, 0, 1, 2}));
InfoL << hexdump(&chunk, StatusVecChunk::kSize) << chunk.dumpString();
}
}
#endif

View File

@ -346,14 +346,16 @@ enum class SymbolStatus : uint8_t{
class FCI_TWCC{ class FCI_TWCC{
public: public:
static size_t constexpr kSize = 8; static size_t constexpr kSize = 8;
using TwccPacketStatus = map<uint16_t/*rtp ext seq*/, std::pair<SymbolStatus, int16_t/*recv delta,单位为250us*/> >;
void check(size_t size); void check(size_t size);
string dumpString(size_t total_size) const; string dumpString(size_t total_size) const;
uint16_t getBaseSeq() const; uint16_t getBaseSeq() const;
//单位64ms //单位64ms
uint32_t getReferenceTime() const; uint32_t getReferenceTime() const;
uint16_t getPacketCount() const; uint16_t getPacketCount() const;
map<uint16_t/*rtp ext seq*/, std::pair<SymbolStatus, int16_t/*recv delta,单位为250us*/> > getPacketChunkList(size_t total_size) const; TwccPacketStatus getPacketChunkList(size_t total_size) const;
static string create(uint32_t ref_time, uint8_t fb_pkt_count, TwccPacketStatus &status);
private: private:
//base sequence number,基础序号,本次反馈的第一个包的序号;也就是RTP扩展头的序列号 //base sequence number,基础序号,本次反馈的第一个包的序号;也就是RTP扩展头的序列号

View File

@ -1,25 +0,0 @@
/*
* 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 <iostream>
#include "Util/logger.h"
#include "Rtcp/RtcpFCI.h"
using namespace std;
using namespace toolkit;
using namespace mediakit;
extern void testFCI();
int main() {
Logger::Instance().add(std::make_shared<ConsoleChannel>());
testFCI();
return 0;
}

View File

@ -9,6 +9,9 @@
*/ */
#include "TwccContext.h" #include "TwccContext.h"
#include "Rtcp/RtcpFCI.h"
using namespace mediakit;
enum class ExtSeqStatus : int { enum class ExtSeqStatus : int {
normal = 0, normal = 0,
@ -78,17 +81,27 @@ void TwccContext::onSendTwcc() {
auto begin = _rtp_recv_status.begin(); auto begin = _rtp_recv_status.begin();
auto min = begin->first; auto min = begin->first;
auto ref_time = begin->second; auto ref_time = begin->second;
DebugL << "base_seq:" << min << ",pkt_status_count:" << max + 1 - min << ",ref time:" << ref_time / 64 FCI_TWCC::TwccPacketStatus status;
<< ", fb count:" << (int) (_twcc_pkt_count++); for (auto seq = min; seq <= max; ++seq) {
for (auto i = min; i <= max; ++i) { int16_t delta = 0;
auto it = _rtp_recv_status.find(i); SymbolStatus symbol = SymbolStatus::not_received;
if (it == _rtp_recv_status.end()) { auto it = _rtp_recv_status.find(seq);
DebugL << "rtp seq:" << i << ",packet status:" << 0 /*not recved*/ << ",delta_ms:" << 0; if (it != _rtp_recv_status.end()) {
//recv delta,单位为250us,1ms等于4x250us
delta = (int16_t) (4 * ((int64_t) it->second - (int64_t) ref_time));
if (delta < 0 || delta > 0xFF) {
symbol = SymbolStatus::large_delta;
} else { } else {
auto delta_ms = it->second - ref_time; symbol = SymbolStatus::small_delta;
DebugL << "rtp seq:" << i << ",packet status:" << 1 /*recved*/ << ",delta_ms:" << delta_ms;
} }
ref_time = it->second;
} }
status.emplace(seq, std::make_pair(symbol, delta));
}
auto fci = FCI_TWCC::create(ref_time / 64, _twcc_pkt_count, status);
InfoL << ((FCI_TWCC *) (fci.data()))->dumpString(fci.size());
++_twcc_pkt_count;
clearStatus(); clearStatus();
} }