Commit 9d9f6e30 by xiongziliang

完善dts计算算法

parent 3630839b
...@@ -95,7 +95,7 @@ int64_t Stamp::getRelativeStamp() const { ...@@ -95,7 +95,7 @@ int64_t Stamp::getRelativeStamp() const {
bool DtsGenerator::getDts(uint32_t pts, uint32_t &dts){ bool DtsGenerator::getDts(uint32_t pts, uint32_t &dts){
bool ret = false; bool ret = false;
if(pts == _last_pts){ if(pts == _last_pts){
//pts未变,返回上次结果 //pts未变,说明dts也不会变,返回上次dts
if(_last_dts){ if(_last_dts){
dts = _last_dts; dts = _last_dts;
ret = true; ret = true;
...@@ -105,44 +105,68 @@ bool DtsGenerator::getDts(uint32_t pts, uint32_t &dts){ ...@@ -105,44 +105,68 @@ bool DtsGenerator::getDts(uint32_t pts, uint32_t &dts){
ret = getDts_l(pts,dts); ret = getDts_l(pts,dts);
if(ret){ if(ret){
//保存本次结果 //获取到了dts,保存本次结果
_last_dts = dts; _last_dts = dts;
}else{
//pts排序列队长度还不知道,也就是不知道有没有B帧,
//那么先强制dts == pts,这样可能导致有B帧的情况下,起始画面有几帧回退
dts = pts;
} }
//记录上次pts //记录上次pts
_last_pts = pts; _last_pts = pts;
return ret; return ret;
} }
//该算法核心思想是对pts进行排序,排序好的pts就是dts。
//排序有一定的滞后性,那么需要加上排序导致的时间戳偏移量
bool DtsGenerator::getDts_l(uint32_t pts, uint32_t &dts){ bool DtsGenerator::getDts_l(uint32_t pts, uint32_t &dts){
if(_sorter_max_size == 1){ if(_sorter_max_size == 1){
//没有B帧 //没有B帧,dts就等于pts
dts = pts; dts = pts;
return true; return true;
} }
if(!_sorter_max_size){ if(!_sorter_max_size){
//尚未计算出pts排序列队长度(也就是P帧间B帧个数)
if(pts > _last_max_pts){ if(pts > _last_max_pts){
//pts时间戳增加了,那么说明这帧画面不是B帧(说明是P帧或关键帧)
if(_frames_since_last_max_pts && _count_sorter_max_size++ > 0){ if(_frames_since_last_max_pts && _count_sorter_max_size++ > 0){
//已经出现多次非B帧的情况,那么我们就能知道P帧间B帧的个数
_sorter_max_size = _frames_since_last_max_pts; _sorter_max_size = _frames_since_last_max_pts;
//我们记录P帧间时间间隔(也就是多个B帧时间戳增量累计)
_dts_pts_offset = (pts - _last_max_pts) / 2; _dts_pts_offset = (pts - _last_max_pts) / 2;
} }
//遇到P帧或关键帧,连续B帧计数清零
_frames_since_last_max_pts = 0; _frames_since_last_max_pts = 0;
//记录上次非B帧的pts时间戳(同时也是dts),用于统计连续B帧时间戳增量
_last_max_pts = pts; _last_max_pts = pts;
} }
//如果pts时间戳小于上一个P帧,那么断定这个是B帧,我们记录B帧连续个数
++_frames_since_last_max_pts; ++_frames_since_last_max_pts;
} }
//pts放入排序缓存列队,缓存列队最大等于连续B帧个数
_pts_sorter.emplace(pts); _pts_sorter.emplace(pts);
if(_sorter_max_size && _pts_sorter.size() > _sorter_max_size){ if(_sorter_max_size && _pts_sorter.size() > _sorter_max_size){
//如果启用了pts排序(意味着存在B帧),并且pts排序缓存列队长度大于连续B帧个数,
//意味着后续的pts都会比最早的pts大,那么说明可以取出最早的pts了,这个pts将当做该帧的dts基准
auto it = _pts_sorter.begin(); auto it = _pts_sorter.begin();
//由于该pts是前面偏移了个_sorter_max_size帧的pts(也就是那帧画面的dts),
//那么我们加上时间戳偏移量,基本等于该帧的dts
dts = *it + _dts_pts_offset; dts = *it + _dts_pts_offset;
if(dts > pts){ if(dts > pts){
//dts不能大于pts(基本不可能到达这个逻辑) //dts不能大于pts(基本不可能到达这个逻辑)
dts = pts; dts = pts;
} }
//pts排序缓存出列
_pts_sorter.erase(it); _pts_sorter.erase(it);
return true; return true;
} }
//排序缓存尚未满
return false; return false;
} }
......
...@@ -191,19 +191,10 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) { ...@@ -191,19 +191,10 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
} }
void H264RtpDecoder::onGetH264(const H264Frame::Ptr &frame) { void H264RtpDecoder::onGetH264(const H264Frame::Ptr &frame) {
auto flag = _dts_generator.getDts(frame->_pts,frame->_dts); //rtsp没有dts,那么根据pts排序算法生成dts
if(!flag){ _dts_generator.getDts(frame->_pts,frame->_dts);
if(frame->configFrame() || frame->keyFrame()){ //写入环形缓存
flag = true; RtpCodec::inputFrame(frame);
frame->_dts = frame->_pts;
}
}
//根据pts计算dts
if(flag){
//写入环形缓存
RtpCodec::inputFrame(frame);
}
_h264frame = obtainFrame(); _h264frame = obtainFrame();
} }
......
...@@ -127,18 +127,10 @@ bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) { ...@@ -127,18 +127,10 @@ bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtppack) {
} }
void H265RtpDecoder::onGetH265(const H265Frame::Ptr &frame) { void H265RtpDecoder::onGetH265(const H265Frame::Ptr &frame) {
//计算dts //rtsp没有dts,那么根据pts排序算法生成dts
auto flag = _dts_generator.getDts(frame->_pts,frame->_dts); _dts_generator.getDts(frame->_pts,frame->_dts);
if(!flag){ //写入环形缓存
if(frame->configFrame() || frame->keyFrame()){ RtpCodec::inputFrame(frame);
flag = true;
frame->_dts = frame->_pts;
}
}
if(flag){
//写入环形缓存
RtpCodec::inputFrame(frame);
}
_h265frame = obtainFrame(); _h265frame = obtainFrame();
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论