diff --git a/src/Common/Stamp.cpp b/src/Common/Stamp.cpp index ecc52e81..fa449721 100644 --- a/src/Common/Stamp.cpp +++ b/src/Common/Stamp.cpp @@ -42,7 +42,40 @@ void Stamp::setPlayBack(bool playback) { _playback = playback; } +void Stamp::makeRelation(Stamp &other){ + _related = &other; +} + 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); + if(modifyStamp || _playback){ + //自动生成时间戳或回放,不需要做音视频同步 + return; + } + + if(_related && _related->_last_dts){ + //音视频dts当前时间差 + int64_t dts_diff = _last_dts - _related->_last_dts; + if(ABS(dts_diff) < 5000){ + //如果绝对时间戳小于5秒,那么说明他们的起始时间戳是一致的,那么强制同步 + _last_relativeStamp = _relativeStamp; + _relativeStamp = _related->_relativeStamp + dts_diff; + dts_out += dts_diff; + pts_out += dts_diff; +// DebugL << "音视频同步事件差:" << dts_diff; + } + //下次不用再强制同步 + _related = nullptr; + } + + if(dts_out < 0){ + //相对时间戳小于0,那么说明是同步时间戳导致的,在这个过渡期内,我们一直返回上次的结果(目的是为了防止时间戳回退) + pts_out = _last_relativeStamp + (pts_out - dts_out); + dts_out = _last_relativeStamp; + } +} + +void Stamp::revise_l(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out,bool modifyStamp) { if(!pts){ //没有播放时间戳,使其赋值为解码时间戳 pts = dts; @@ -53,6 +86,7 @@ void Stamp::revise(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out, dts_out = dts; pts_out = pts; _relativeStamp = dts_out; + _last_dts = dts; return; } @@ -62,6 +96,7 @@ void Stamp::revise(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out, if(_last_dts != dts){ //时间戳发生变更 if(modifyStamp){ + //内部自己生产时间戳 _relativeStamp = _ticker.elapsedTime(); }else{ _relativeStamp += deltaStamp(dts); diff --git a/src/Common/Stamp.h b/src/Common/Stamp.h index 9e49f393..2b57f7c0 100644 --- a/src/Common/Stamp.h +++ b/src/Common/Stamp.h @@ -32,6 +32,7 @@ public: private: int64_t _last_stamp = 0; }; + //该类解决时间戳回环、回退问题 //计算相对时间戳或者产生平滑时间戳 class Stamp : public DeltaStamp{ @@ -66,14 +67,25 @@ public: * @param playback 是否为回放模式 */ void setPlayBack(bool playback = true); + + /** + * 产生关联,用于音视频同步用 + */ + void makeRelation(Stamp &other); + +private: + void revise_l(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out,bool modifyStamp = false); private: int64_t _relativeStamp = 0; - int64_t _last_dts = -1; + int64_t _last_relativeStamp = 0; + int64_t _last_dts = 0; SmoothTicker _ticker; bool _playback = false; + Stamp *_related = nullptr; }; - +//dts生成器, +//pts排序后就是dts class DtsGenerator{ public: DtsGenerator() = default; @@ -90,8 +102,6 @@ private: int _sorter_max_size = 0; int _count_sorter_max_size = 0; set _pts_sorter; - - }; }//namespace mediakit diff --git a/src/Rtmp/FlvMuxer.cpp b/src/Rtmp/FlvMuxer.cpp index 94ad3996..456f679b 100644 --- a/src/Rtmp/FlvMuxer.cpp +++ b/src/Rtmp/FlvMuxer.cpp @@ -50,6 +50,9 @@ void FlvMuxer::start(const EventPoller::Ptr &poller,const RtmpMediaSource::Ptr & } strongSelf->onDetach(); }); + + //音频同步于视频 + _stamp[0].makeRelation( _stamp[1]); _ring_reader->setReadCB([weakSelf](const RtmpMediaSource::RingDataType &pkt){ auto strongSelf = weakSelf.lock(); if(!strongSelf){ diff --git a/src/Rtmp/RtmpSession.cpp b/src/Rtmp/RtmpSession.cpp index a062c5d6..873b1726 100644 --- a/src/Rtmp/RtmpSession.cpp +++ b/src/Rtmp/RtmpSession.cpp @@ -266,6 +266,8 @@ void RtmpSession::sendPlayResponse(const string &err,const RtmpMediaSource::Ptr onSendMedia(pkt); }); + //音频同步于视频 + _stamp[0].makeRelation( _stamp[1]); _pRingReader = src->getRing()->attach(getPoller()); weak_ptr weakSelf = dynamic_pointer_cast(shared_from_this()); _pRingReader->setReadCB([weakSelf](const RtmpMediaSource::RingDataType &pkt) {