mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2026-07-28 13:04:07 +08:00
重构平滑发送逻辑,自适应发送速度降低延时
This commit is contained in:
@@ -36,14 +36,17 @@ public:
|
|||||||
class FramePacedSender : public FrameWriterInterface, public std::enable_shared_from_this<FramePacedSender> {
|
class FramePacedSender : public FrameWriterInterface, public std::enable_shared_from_this<FramePacedSender> {
|
||||||
public:
|
public:
|
||||||
using OnFrame = std::function<void(const Frame::Ptr &frame)>;
|
using OnFrame = std::function<void(const Frame::Ptr &frame)>;
|
||||||
// 最小缓存100ms数据 [AUTO-TRANSLATED:7b2fcb0d]
|
|
||||||
// Minimum cache 100ms data
|
|
||||||
static constexpr auto kMinCacheMS = 100;
|
|
||||||
|
|
||||||
FramePacedSender(uint32_t paced_sender_ms, OnFrame cb) {
|
// Buffer depth thresholds (ms)
|
||||||
_paced_sender_ms = paced_sender_ms;
|
static constexpr int kLowMS = 100; // Below this → slow down
|
||||||
_cb = std::move(cb);
|
static constexpr int kTargetMS = 200; // Upper bound of normal-speed zone
|
||||||
}
|
static constexpr int kHighMS = 500; // Above this → max speed + force flush
|
||||||
|
// Speed bounds
|
||||||
|
static constexpr float kMinSpeed = 0.5f;
|
||||||
|
static constexpr float kMaxSpeed = 1.5f;
|
||||||
|
|
||||||
|
FramePacedSender(uint32_t paced_sender_ms, OnFrame cb)
|
||||||
|
: _paced_sender_ms(paced_sender_ms), _cb(std::move(cb)) {}
|
||||||
|
|
||||||
void resetTimer(const EventPoller::Ptr &poller) {
|
void resetTimer(const EventPoller::Ptr &poller) {
|
||||||
std::lock_guard<std::recursive_mutex> lck(_mtx);
|
std::lock_guard<std::recursive_mutex> lck(_mtx);
|
||||||
@@ -65,8 +68,8 @@ public:
|
|||||||
}
|
}
|
||||||
auto &last_dts = _last_dts[frame->getTrackType()];
|
auto &last_dts = _last_dts[frame->getTrackType()];
|
||||||
if (last_dts > frame->dts()) {
|
if (last_dts > frame->dts()) {
|
||||||
// 时间戳回退了,点播流?
|
WarnL << "Dts decrease: " << last_dts << "->" << frame->dts()
|
||||||
WarnL << "Dts decrease: " << last_dts << "->" << frame->dts() << ", flush all paced sender cache: " << _cache.size();
|
<< ", flush paced sender cache: " << _cache.size();
|
||||||
flushCache(frame->dts());
|
flushCache(frame->dts());
|
||||||
}
|
}
|
||||||
_cache.emplace(frame->dts(), Frame::getCacheAbleFrame(frame));
|
_cache.emplace(frame->dts(), Frame::getCacheAbleFrame(frame));
|
||||||
@@ -75,34 +78,56 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* Compute playback speed multiplier from buffer depth (ms).
|
||||||
|
*
|
||||||
|
* buf < kLowMS → slow down (kMinSpeed … 1.0)
|
||||||
|
* kLowMS ≤ buf ≤ kTargetMS → normal (1.0)
|
||||||
|
* kTargetMS < buf ≤ kHighMS → speed up (1.0 … kMaxSpeed)
|
||||||
|
* buf > kHighMS → max speed (kMaxSpeed) + force flush
|
||||||
|
*/
|
||||||
|
float calcSpeed(int buf_ms) const {
|
||||||
|
if (buf_ms < kLowMS) {
|
||||||
|
float t = (float)buf_ms / kLowMS;
|
||||||
|
return kMinSpeed + t * (1.0f - kMinSpeed);
|
||||||
|
}
|
||||||
|
if (buf_ms <= kTargetMS) {
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
if (buf_ms <= kHighMS) {
|
||||||
|
float t = (float)(buf_ms - kTargetMS) / (kHighMS - kTargetMS);
|
||||||
|
return 1.0f + t * (kMaxSpeed - 1.0f);
|
||||||
|
}
|
||||||
|
return kMaxSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
void onTick() {
|
void onTick() {
|
||||||
std::lock_guard<std::recursive_mutex> lck(_mtx);
|
std::lock_guard<std::recursive_mutex> lck(_mtx);
|
||||||
auto max_dts = _cache.empty() ? 0 : _cache.rbegin()->first;
|
|
||||||
|
uint64_t wall_ms = _ticker.elapsedTime();
|
||||||
|
_ticker.resetTime();
|
||||||
|
|
||||||
|
// Buffer depth = newest dts − oldest dts in cache
|
||||||
|
int buf_ms = 0;
|
||||||
|
if (_cache.size() >= 2) {
|
||||||
|
buf_ms = (int)(_cache.rbegin()->first - _cache.begin()->first);
|
||||||
|
}
|
||||||
|
|
||||||
|
float speed = calcSpeed(buf_ms);
|
||||||
|
_virtual_pos += (uint64_t)(wall_ms * speed);
|
||||||
|
|
||||||
|
// Consume frames whose dts ≤ virtual position
|
||||||
while (!_cache.empty()) {
|
while (!_cache.empty()) {
|
||||||
auto front = _cache.begin();
|
auto front = _cache.begin();
|
||||||
if (getCurrentStamp() < front->first + _cache_ms) {
|
if (front->first > _virtual_pos) break;
|
||||||
// 还没到消费时间 [AUTO-TRANSLATED:09fb4c3d]
|
|
||||||
// Not yet time to consume
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// 时间到了,该消费frame了 [AUTO-TRANSLATED:2f007931]
|
|
||||||
// Time is up, it's time to consume the frame
|
|
||||||
_cb(front->second);
|
_cb(front->second);
|
||||||
_cache.erase(front);
|
_cache.erase(front);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_cache.empty() && max_dts) {
|
// Safety flush when buffer grows too deep
|
||||||
// 消费太快,需要增加缓存大小 [AUTO-TRANSLATED:c05bfbcd]
|
if (buf_ms > kHighMS * 2) {
|
||||||
// Consumption is too fast, need to increase cache size
|
WarnL << "Force flush paced sender cache: buf=" << buf_ms << "ms";
|
||||||
setCurrentStamp(max_dts);
|
flushCache(_cache.empty() ? _virtual_pos : _cache.rbegin()->first);
|
||||||
_cache_ms += kMinCacheMS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 消费太慢,需要强制flush数据 [AUTO-TRANSLATED:5613625e]
|
|
||||||
// Consumption is too slow, need to force flush data
|
|
||||||
if (_cache.size() > 25 * 5) {
|
|
||||||
WarnL << "Flush frame paced sender cache: " << _cache.size();
|
|
||||||
flushCache(max_dts);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,20 +138,16 @@ private:
|
|||||||
_cache.erase(front);
|
_cache.erase(front);
|
||||||
}
|
}
|
||||||
setCurrentStamp(dts);
|
setCurrentStamp(dts);
|
||||||
_cache_ms = kMinCacheMS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t getCurrentStamp() { return _ticker.elapsedTime() + _stamp_offset; }
|
|
||||||
|
|
||||||
void setCurrentStamp(uint64_t stamp) {
|
void setCurrentStamp(uint64_t stamp) {
|
||||||
_stamp_offset = stamp;
|
_virtual_pos = stamp;
|
||||||
_ticker.resetTime();
|
_ticker.resetTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t _paced_sender_ms;
|
uint32_t _paced_sender_ms;
|
||||||
uint32_t _cache_ms = kMinCacheMS;
|
uint64_t _virtual_pos = 0;
|
||||||
uint64_t _stamp_offset = 0;
|
|
||||||
uint64_t _last_dts[2] = {0, 0};
|
uint64_t _last_dts[2] = {0, 0};
|
||||||
OnFrame _cb;
|
OnFrame _cb;
|
||||||
Ticker _ticker;
|
Ticker _ticker;
|
||||||
|
|||||||
Reference in New Issue
Block a user