diff --git a/src/Common/Stamp.cpp b/src/Common/Stamp.cpp index 2656a176..47d344a7 100644 --- a/src/Common/Stamp.cpp +++ b/src/Common/Stamp.cpp @@ -20,8 +20,13 @@ using namespace toolkit; namespace mediakit { -int64_t DeltaStamp::relativeStamp(int64_t stamp) { - _relative_stamp += deltaStamp(stamp); +DeltaStamp::DeltaStamp() { + // 时间戳最大允许跳跃300ms + _max_delta = 300; +} + +int64_t DeltaStamp::relativeStamp(int64_t stamp, bool enable_rollback) { + _relative_stamp += deltaStamp(stamp, enable_rollback); return _relative_stamp; } @@ -29,7 +34,7 @@ int64_t DeltaStamp::relativeStamp() { return _relative_stamp; } -int64_t DeltaStamp::deltaStamp(int64_t stamp) { +int64_t DeltaStamp::deltaStamp(int64_t stamp, bool enable_rollback) { if (!_last_stamp) { // 第一次计算时间戳增量,时间戳增量为0 if (stamp) { @@ -43,14 +48,25 @@ int64_t DeltaStamp::deltaStamp(int64_t stamp) { // 时间戳增量为正,返回之 _last_stamp = stamp; // 在直播情况下,时间戳增量不得大于MAX_DELTA_STAMP,否则强制相对时间戳加1 - return ret < MAX_DELTA_STAMP ? ret : 1; + if (ret > _max_delta) { + needSync(); + return 1; + } + return ret; } // 时间戳增量为负,说明时间戳回环了或回退了 _last_stamp = stamp; + if (!enable_rollback || -ret > _max_delta) { + // 不允许回退或者回退太多了, 强制时间戳加1 + needSync(); + return 1; + } + return ret; +} - // 如果时间戳回退不多,那么返回负值,否则返回加1 - return -ret < MAX_DELTA_STAMP ? ret : 1; +void DeltaStamp::setMaxDelta(size_t max_delta) { + _max_delta = max_delta; } void Stamp::setPlayBack(bool playback) { @@ -58,9 +74,18 @@ void Stamp::setPlayBack(bool playback) { } void Stamp::syncTo(Stamp &other) { + _need_sync = true; _sync_master = &other; } +void Stamp::needSync() { + _need_sync = true; +} + +void Stamp::enableRollback(bool flag) { + _enable_rollback = flag; +} + // 限制dts回退 void Stamp::revise(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out, bool modifyStamp) { revise_l(dts, pts, dts_out, pts_out, modifyStamp); @@ -87,15 +112,26 @@ void Stamp::revise_l(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_ou return; } - if (_sync_master && _sync_master->_last_dts_in) { + // 需要同步时间戳 + if (_sync_master && _sync_master->_last_dts_in && (_need_sync || _sync_master->_need_sync)) { // 音视频dts当前时间差 int64_t dts_diff = _last_dts_in - _sync_master->_last_dts_in; if (ABS(dts_diff) < 5000) { // 如果绝对时间戳小于5秒,那么说明他们的起始时间戳是一致的,那么强制同步 - _relative_stamp = _sync_master->_relative_stamp + dts_diff; + auto target_stamp = _sync_master->_relative_stamp + dts_diff; + if (target_stamp > _relative_stamp || _enable_rollback) { + // 强制同步后,时间戳增加跳跃了,或允许回退 + TraceL << "Relative stamp changed: " << _relative_stamp << " -> " << target_stamp; + _relative_stamp = target_stamp; + } else { + // 不允许回退, 则让另外一个Track的时间戳增长 + target_stamp = _relative_stamp - dts_diff; + TraceL << "Relative stamp changed: " << _sync_master->_relative_stamp << " -> " << target_stamp; + _sync_master->_relative_stamp = target_stamp; + } } - // 下次不用再强制同步 - _sync_master = nullptr; + _need_sync = false; + _sync_master->_need_sync = false; } } @@ -124,7 +160,7 @@ void Stamp::revise_l2(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_o // 内部自己生产时间戳 _relative_stamp = _ticker.elapsedTime(); } else { - _relative_stamp += deltaStamp(dts); + _relative_stamp += deltaStamp(dts, _enable_rollback); } _last_dts_in = dts; } diff --git a/src/Common/Stamp.h b/src/Common/Stamp.h index 03cb7bb7..243c250c 100644 --- a/src/Common/Stamp.h +++ b/src/Common/Stamp.h @@ -19,19 +19,27 @@ namespace mediakit { class DeltaStamp{ public: - DeltaStamp() = default; + DeltaStamp(); ~DeltaStamp() = default; /** * 计算时间戳增量 * @param stamp 绝对时间戳 + * @param enable_rollback 是否允许相当时间戳回退 * @return 时间戳增量 */ - int64_t deltaStamp(int64_t stamp); - int64_t relativeStamp(int64_t stamp); + int64_t deltaStamp(int64_t stamp, bool enable_rollback = true); + int64_t relativeStamp(int64_t stamp, bool enable_rollback = true); int64_t relativeStamp(); -private: + // 设置最大允许回退或跳跃幅度 + void setMaxDelta(size_t max_delta); + +protected: + virtual void needSync() {} + +protected: + int _max_delta; int64_t _last_stamp = 0; int64_t _relative_stamp = 0; }; @@ -77,6 +85,11 @@ public: */ void syncTo(Stamp &other); + /** + * 是否允许时间戳回退 + */ + void enableRollback(bool flag); + private: //主要实现音视频时间戳同步功能 void revise_l(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out,bool modifyStamp = false); @@ -84,13 +97,18 @@ private: //主要实现获取相对时间戳功能 void revise_l2(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out,bool modifyStamp = false); + void needSync() override; + private: + bool _playback = false; + bool _need_sync = false; + // 默认不允许时间戳回滚 + bool _enable_rollback = false; int64_t _relative_stamp = 0; int64_t _last_dts_in = 0; int64_t _last_dts_out = 0; int64_t _last_pts_out = 0; toolkit::SmoothTicker _ticker; - bool _playback = false; Stamp *_sync_master = nullptr; }; diff --git a/src/Rtsp/RtspMuxer.cpp b/src/Rtsp/RtspMuxer.cpp index 6f5e4f8f..1665000c 100644 --- a/src/Rtsp/RtspMuxer.cpp +++ b/src/Rtsp/RtspMuxer.cpp @@ -14,7 +14,7 @@ using namespace std; using namespace toolkit; -#define ENABLE_NTP_STAMP 0 +#define ENABLE_NTP_STAMP 1 namespace mediakit { @@ -78,6 +78,10 @@ bool RtspMuxer::addTrack(const Track::Ptr &track) { //添加其sdp _sdp.append(sdp->getSdp()); trySyncTrack(); + + // rtp的时间戳是pts,允许回退 + _stamp[TrackAudio].enableRollback(true); + _stamp[TrackVideo].enableRollback(true); return true; }