webrtc jitter buffer
?一、jitter buffer 介紹
?二、jitter 估計(jì)
?三、buffer 處理 rtp 包邏輯
?四、接收和解碼流程
?五、FrameBuffer 類(lèi)介紹
/*
?********************************************************************************
?一、jitter buffer 介紹
?jitter buffer 抖動(dòng)緩沖區(qū)
? ?當(dāng)網(wǎng)絡(luò)不穩(wěn)定時(shí)(發(fā)生抖動(dòng)),增加buffer的長(zhǎng)度,多緩存一些數(shù)據(jù),以應(yīng)對(duì)將來(lái)可能發(fā)生的抖動(dòng)。
? ?它對(duì)數(shù)據(jù)包丟失、亂序、延遲到達(dá)等情況進(jìn)行處理,平滑的向解碼模塊輸出數(shù)據(jù)包/幀,
?抵抗各種弱網(wǎng)情況對(duì)播放/渲染造成的影響,降低卡頓,提高用戶體驗(yàn)。
?視頻從采集到渲染的流程如下:
?采集 -> 編碼 -> 分包 -> 發(fā)送 ----------------> 網(wǎng)絡(luò)
?渲染 <- 解碼 <- Jitter Buffer <- 組幀 <- 接收 <-|
?********************************************************************************
?*/
/*
?********************************************************************************
?二、jitter 估計(jì)
?
?jitter 就是一種抖動(dòng)。
?RTP數(shù)據(jù)包從源地址發(fā)送到目的地址,會(huì)發(fā)生不一樣的延遲,這樣的延遲變動(dòng)就是 jitter
?jitter 會(huì)讓音視頻的播放不穩(wěn)定,如音頻的顫音、視頻的忽快忽慢
?解決 jitter 的方法是增加延時(shí),這個(gè)延時(shí)稱(chēng)為抖動(dòng)延遲(jitter delay)
?抖動(dòng)延遲由網(wǎng)絡(luò)延遲、解碼延遲、渲染延遲構(gòu)成。解碼、渲染延遲比較穩(wěn)定,網(wǎng)絡(luò)抖動(dòng)延遲是動(dòng)態(tài)變化的。
?webrtc 認(rèn)為網(wǎng)絡(luò)抖動(dòng)延遲由兩部分構(gòu)成:
?1、網(wǎng)絡(luò)噪聲帶來(lái)的抖動(dòng)延遲(網(wǎng)絡(luò)排隊(duì)延遲)
?2、傳輸大的視頻幀(特別是關(guān)鍵幀)對(duì)網(wǎng)絡(luò)造成沖擊帶來(lái)的抖動(dòng)延遲
? ?(計(jì)算信道速率,根據(jù)信道速率計(jì)算大的視頻幀對(duì)網(wǎng)絡(luò)沖擊帶來(lái)的延遲)
?webrtc 使用卡爾曼濾波(kalman) 估算網(wǎng)絡(luò)排隊(duì)延遲和信道速率
?modules\video_coding\jitter_estimator.cc
?1、更新 jitter 估計(jì)
?void VCMJitterEstimator::UpdateEstimate(
? ?int64_t frameDelayMS, uint32_t frameSizeBytes, bool incompleteFrame = false);
?
?其中 frameDelayMS 幀間延遲,指的是一幀數(shù)據(jù)因?yàn)榉职途W(wǎng)絡(luò)傳輸所造成的延時(shí)。
?frameSizeBytes 指當(dāng)前數(shù)據(jù)幀大小, incompleteFrame 指是否為完整的幀。
?1.1、噪聲閾值計(jì)算
?VCMJitterEstimator::NoiseThreshold()
? ?double noiseThreshold = _noiseStdDevs * sqrt(_varNoise) - _noiseStdDevOffset;
?1.2、計(jì)算 jitter 估計(jì)值
?VCMJitterEstimator::CalculateEstimate()
? ?double ret = _theta[0] * (_maxFrameSize - _avgFrameSize) + NoiseThreshold();
?
?即
?jitterDelay = _theta[0] * (_maxFrameSize - _avgFrameSize)
? ? ? ? ? ? ? ?+ _noiseStdDevs * sqrt(_varNoise) - _noiseStdDevOffset;?
?
?其中:
?_theta[0] 為信道傳輸速率的倒數(shù)
?_maxFrameSize 自會(huì)話開(kāi)始以來(lái)所收到的最大幀大小
?_avgFrameSize 平均幀大小
?_noiseStdDevs 表示噪聲系數(shù),值為2.33
?_varNoise 表示噪聲方差,默認(rèn)值為4.0 EstimateRandomJitter()中會(huì)不斷更新該值
?_noiseStdDevOffset 為噪聲扣除常數(shù),值為30.0
?2、獲取 jitter 估計(jì)
?返回以毫秒為單位的當(dāng)前抖動(dòng)估計(jì),并在重傳情況下添加一個(gè)RTT相關(guān)項(xiàng)
?int VCMJitterEstimator::GetJitterEstimate(
? ?double rttMultiplier, absl::optional<double> rttMultAddCapMs)
?其中: rttMultiplier 為RTT參數(shù)乘數(shù)
?參考: http://www.ctiforum.com/news/guonei/512085.html
?********************************************************************************
?*/
/*
?********************************************************************************
?三、buffer 處理 rtp 包邏輯
?modules\video_coding\jitter_buffer.h
?buffer 接收 rtp 包的處理邏輯主要使用到以下三個(gè)隊(duì)列
?class VCMJitterBuffer {
? ?UnorderedFrameList free_frames_ RTC_GUARDED_BY(crit_sect_);
? ?FrameList decodable_frames_ RTC_GUARDED_BY(crit_sect_);
? ?FrameList incomplete_frames_ RTC_GUARDED_BY(crit_sect_);
?}
?free_frames_ 隊(duì)列用于管理空的frame,彈出空的frame來(lái)存放rtp包,解碼完成后的frame重置后再次存入該隊(duì)列。
?incomplete_frames_ 隊(duì)列用于存放尚未完整的frame,當(dāng)frame完整時(shí)將其push到 decodable_frames_
?decodable_frames_ 隊(duì)列用于存放完整的可以解碼的frame
?
?1、第一次接收到一個(gè)rtp視頻包,從 free_frames_ 隊(duì)列中彈出一個(gè)空 frame 塊,用來(lái)放置這個(gè)包。
? ? 之后每次接收一個(gè)rtp包,根據(jù)時(shí)間戳在 incomplete_frames_ 和 decodable_frames_?
? ? 中尋找,看是否已經(jīng)接收到過(guò)相同時(shí)間戳的包,如果找到則彈出該 frame 塊。
? ? 否則,從 free_frames_ 中彈出一個(gè)空 frame
?2、根據(jù)包的序列號(hào),找到應(yīng)該插入 frame 的位置將包插入,并更新 frame 的 state (frame中存放多個(gè)rtp包)
? ? 其中 state 的狀態(tài)為?
? ? enum VCMFrameBufferStateEnum {
? ? ? kStateEmpty, ? ? ? // frame popped by the RTP receiver
? ? ? kStateIncomplete, ?// frame that have one or more packet(s) stored
? ? ? kStateComplete, ? ?// frame that have all packets
? ? };
?3、根據(jù)不同的 buffer_state 將 frame 幀 push 回到隊(duì)列中。
? ? 如果 buffer_state 為 kCompleteSession 并且 frame 已經(jīng)在 decodable list (continuous 為 true)
? ? 將 frame push 到 decodable_frames_ 隊(duì)列 decodable_frames_.InsertFrame(frame);
? ? 如果 buffer_state 為 kCompleteSession 或 kIncomplete
? ? 將 frame push 到 incomplete_frames_ 隊(duì)列 incomplete_frames_.InsertFrame(frame);
? ? 如果 buffer_state 為 kNoError 或 kOutOfBoundsPacket 或 kDuplicatePacket
? ? 將 frame push 到 frame_list 隊(duì)列 frame_list->InsertFrame(frame);
? ? VCMJitterBuffer::InsertPacket -> VCMJitterBuffer::FindAndInsertContinuousFramesWithState()?
? ? 將 incomplete_frames_ 隊(duì)列中的 frame push 到 decodable_frames_ 隊(duì)列
?
?4、free_frames_ 隊(duì)列初始化大小為 kStartNumberOfFrames = 6 (在構(gòu)造函數(shù) VCMJitterBuffer() 中初始化)
? ? 如果 free_frames_ 隊(duì)列為空時(shí),增加隊(duì)列大小,最大值為 kMaxNumberOfFrames = 300
? ? 定期從 incomplete_frames_ 和 decodable_frames_ 隊(duì)列中清除一些過(guò)時(shí)的frame?
? ? push 到 free_frames_ 隊(duì)列 VCMJitterBuffer::RecycleFramesUntilKeyFrame()
?
?5、解碼線程取出 frame 并解碼完成后,將 frame 重置并 push 到 free_frames_ 隊(duì)列
? ? VideoReceiver::Decode() -> VCMReceiver::ReleaseFrame() -> VCMJitterBuffer::ReleaseFrame()
? ? -> VCMJitterBuffer::RecycleFrameBuffer() -> frame->Reset()/free_frames_.push_back(frame)
?********************************************************************************
?*/
/*
?********************************************************************************
?四、接收和解碼流程
?webrtc jitter buffer 被兩個(gè)線程操作
?(1) 寫(xiě)線程負(fù)責(zé)組幀之后把數(shù)據(jù)寫(xiě)入 jitter buffer 里
?(2) 讀線程負(fù)責(zé)從 jitter buffer 里讀取數(shù)據(jù)然后解碼
?1、接收數(shù)據(jù)
?1.1、讀線程 創(chuàng)建流程
?WebRtcVideoChannel::WebRtcVideoReceiveStream::WebRtcVideoReceiveStream()
?-> WebRtcVideoChannel::WebRtcVideoReceiveStream::RecreateWebRtcVideoStream()
? ? [調(diào)用 stream_ = call_->CreateVideoReceiveStream(std::move(config));
? ? ?調(diào)用 stream_->Start()
? ? ?其中 stream_ 類(lèi)型為 webrtc::VideoReceiveStream*
? ? ]
? ? [Call::CreateVideoReceiveStream()
? ? ?VideoReceiveStream::Start()
? ? ]
?-> webrtc::VideoReceiveStream* Call::CreateVideoReceiveStream()
? ? [調(diào)用構(gòu)造函數(shù)?
? ? ?VideoReceiveStream::VideoReceiveStream(module_process_thread_.get())
? ? ?其中 Call::Call() 設(shè)置為 module_process_thread_ 為 ModuleProcessThread 線程
? ? ]
? ? [Call::Create(const Call::Config& config)
? ? ? ? [調(diào)用 Create(config, Clock::GetRealTimeClock(),
? ? ? ? ? ? ? ? ? ? ProcessThread::Create("ModuleProcessThread"),
? ? ? ? ? ? ? ? ? ? ProcessThread::Create("PacerThread"));
? ? ? ? ?創(chuàng)建兩個(gè)線程: ModuleProcessThread 和 PacerThread
? ? ? ? ]
? ? ?-> Call::Create()
? ? ? ? [調(diào)用 new internal::Call()]
? ? ?-> Call::Call()
? ? ? ? [其中設(shè)置 module_process_thread_ 為 ModuleProcessThread 線程]
? ? ]
? ? [VideoReceiveStream::VideoReceiveStream()
? ? ? ? [設(shè)置 rtp_stream_sync_(this) 即 rtp_stream_sync_ 為 VideoReceiveStream 類(lèi)型
? ? ? ? ?設(shè)置 process_thread_ 為 ModuleProcessThread 線程
? ? ? ? ?調(diào)用 process_thread_->RegisterModule(&rtp_stream_sync_, RTC_FROM_HERE);
? ? ? ? ]
? ? ]
?-> VideoReceiveStream::Start()
?-> VideoReceiveStream::StartNextDecode()
? ? [將數(shù)據(jù)幀從 jitter buffer 中取出
? ? ?調(diào)用 frame_buffer_->NextFrame()
? ? ]
?1.2、寫(xiě)線程 創(chuàng)建流程
?VideoReceiveStream::VideoReceiveStream()
? ? [創(chuàng)建 rtp_video_stream_receiver_(process_thread_)
? ? ?其中 rtp_video_stream_receiver_ 類(lèi)型為 RtpVideoStreamReceiver
? ? ?process_thread_ 為 ModuleProcessThread 線程
? ? ]
?-> RtpVideoStreamReceiver::RtpVideoStreamReceiver()
? ? [設(shè)置 process_thread_ 為 ModuleProcessThread 線程]
?-> RtpVideoStreamReceiver::OnCompleteFrame() [從網(wǎng)絡(luò)接收到RTP數(shù)據(jù)]
?-> VideoReceiveStream::OnCompleteFrame()
? ? [調(diào)用 frame_buffer_->InsertFrame()]
?-> FrameBuffer::InsertFrame() [將數(shù)據(jù)幀存放到 jitter buffer ]
?2、解碼流程?
?// 創(chuàng)建一個(gè)工作線程,用于解碼數(shù)據(jù)幀
?// 從 frame_buffer_ 中獲取數(shù)據(jù)幀進(jìn)行解碼
?VideoStreamDecoderImpl::VideoStreamDecoderImpl()
? ? [創(chuàng)建線程 PlatformThread 一個(gè)簡(jiǎn)單的工作線程
? ? ?decode_thread_(&DecodeLoop,
? ? ? ? ? ? ? ? ? ? this,
? ? ? ? ? ? ? ? ? ? "video_stream_decoder_decode_thread",
? ? ? ? ? ? ? ? ? ? rtc::kHighestPriority)
? ? ?啟動(dòng)線程 decode_thread_.Start()
? ? ]
?-> VideoStreamDecoderImpl::DecodeLoop(void* ptr)
? ? [auto* vs_decoder = static_cast<VideoStreamDecoderImpl*>(ptr);
? ? ?啟用循環(huán) while (true)
? ? ?DecodeResult decode_result =
? ? ? ? vs_decoder->DecodeNextFrame(max_wait_time_ms, keyframe_required);
? ? ?如果 decode_result 為 kShutdown 則返回?
? ? ]
?-> VideoStreamDecoderImpl::DecodeNextFrame()
? ? [調(diào)用 frame_buffer_.NextFrame()
? ? ?VideoDecoder* decoder = GetDecoder(frame->PayloadType());
? ? ?decoder->Decode()
? ? ]
? ? [FrameBuffer::NextFrame()
? ? ?VideoStreamDecoderImpl::GetDecoder()
? ? ?VideoDecoder::Decode() 純虛函數(shù)
? ? ?[視頻編碼方式(h264 vp8 vp9),下面以vp8為例]
? ? ]
?-> LibvpxVp8Decoder::Decode()
?// 創(chuàng)建一個(gè)任務(wù)隊(duì)列,在上面的工作線程中以異步的方式執(zhí)行任務(wù)
?// 將 frame 存放到 frame_buffer_
?VideoStreamDecoderImpl::VideoStreamDecoderImpl()
? ? [創(chuàng)建任務(wù)隊(duì)列 bookkeeping_queue_(task_queue_factory->CreateTaskQueue())]
?VideoStreamDecoderImpl::OnFrame()
? ? [如果 bookkeeping_queue_.IsCurrent() 為 false
? ? ?調(diào)用 bookkeeping_queue_.PostTask(
? ? ? ? ? ? std::make_unique<OnFrameTask>(std::move(frame), this));
? ? ?其中 OnFrameTask::Run() 調(diào)用?
? ? ?video_stream_decoder_->OnFrame() 即 VideoStreamDecoderImpl::OnFrame()
? ? ]
? ? [調(diào)用 frame_buffer_.InsertFrame(std::move(frame))]
?********************************************************************************
?*/
/*
?********************************************************************************
?五、FrameBuffer 類(lèi)介紹
?********************************************************************************
?*/
/**
?* jitter buffer實(shí)現(xiàn) frame_buffer2.cc?
?* class FrameBuffer
?*?
*/
FrameBuffer(Clock* clock,
? ? ? ? ? ? VCMTiming* timing,
? ? ? ? ? ? VCMReceiveStatisticsCallback* stats_callback);
// Insert a frame into the frame buffer. Returns the picture id
// of the last continuous frame or -1 if there is no continuous frame.
int64_t InsertFrame(std::unique_ptr<EncodedFrame> frame);
// Get the next frame for decoding. Will return at latest after
// |max_wait_time_ms|.
// ?- If a frame is available within |max_wait_time_ms| it will return
// ? ?kFrameFound and set |frame_out| to the resulting frame.
// ?- If no frame is available after |max_wait_time_ms| it will return
// ? ?kTimeout.
// ?- If the FrameBuffer is stopped then it will return kStopped.
ReturnReason NextFrame(int64_t max_wait_time_ms,
? ? ? ? ? ? ? ? ? ? ? ?std::unique_ptr<EncodedFrame>* frame_out,
? ? ? ? ? ? ? ? ? ? ? ?bool keyframe_required);
void NextFrame(
? ? int64_t max_wait_time_ms,
? ? bool keyframe_required,
? ? rtc::TaskQueue* callback_queue,
? ? std::function<void(std::unique_ptr<EncodedFrame>, ReturnReason)> handler);
// Tells the FrameBuffer which protection mode that is in use. Affects
// the frame timing. (影響幀定時(shí))
void SetProtectionMode(VCMVideoProtection mode);
// Start the frame buffer, has no effect if the frame buffer is started.
// The frame buffer is started upon construction.
void Start();
// Stop the frame buffer, causing any sleeping thread in NextFrame to
// return immediately.
void Stop();
// Updates the RTT for jitter buffer estimation.
void UpdateRtt(int64_t rtt_ms);
// Clears the FrameBuffer, removing all the buffered frames.
void Clear();
class FrameBuffer {
?public:
?private:
??
? FrameMap frames_; ?// 只存儲(chǔ)未解碼的幀
? int64_t latest_return_time_ms_; ?// 下次返回幀的時(shí)間
};
void FrameBuffer::NextFrame(
? ? int64_t max_wait_time_ms,
? ? bool keyframe_required,
? ? rtc::TaskQueue* callback_queue,
? ? std::function<void(std::unique_ptr<EncodedFrame>, ReturnReason)> handler) {
? //?
? int64_t latest_return_time_ms =
? ? ? clock_->TimeInMilliseconds() + max_wait_time_ms;
? latest_return_time_ms_ = latest_return_time_ms;
? keyframe_required_ = keyframe_required;
? frame_handler_ = handler;
? callback_queue_ = callback_queue;
? StartWaitForNextFrameOnQueue();
}
void FrameBuffer::StartWaitForNextFrameOnQueue() {
? // 查找下一個(gè)待解碼的幀存放到 frames_to_decode_ 并返回最大等待時(shí)間
? int64_t wait_ms = FindNextFrame(clock_->TimeInMilliseconds());
? // 啟動(dòng)一個(gè)重復(fù)任務(wù)
? // 如果在等待時(shí)間內(nèi)有可以解碼的幀( frames_to_decode_ 不為空)
? // 則調(diào)用 frame_handler_ 處理幀
? callback_task_ = RepeatingTaskHandle::DelayedStart(
? ? ? callback_queue_->Get(), TimeDelta::ms(wait_ms), [this] {
? ? ? ? // 如果這個(gè)任務(wù)沒(méi)有被取消,我們?cè)诘却龝r(shí)沒(méi)有得到任何新的幀,
? ? ? ? // 則繼續(xù) delivery frame
? ? ? ? if (!frames_to_decode_.empty()) {
? ? ? ? ? // 還有 frame 繼續(xù) deliver
? ? ? ? ? frame_handler_(absl::WrapUnique(GetNextFrame()), kFrameFound);
? ? ? ? ? CancelCallback();
? ? ? ? ? return TimeDelta::Zero(); ?// Ignored.
? ? ? ? } else if (clock_->TimeInMilliseconds() >= latest_return_time_ms_) {
? ? ? ? ? // 超時(shí),發(fā)送信號(hào)并停止重復(fù)任務(wù)
? ? ? ? ? frame_handler_(nullptr, kTimeout);
? ? ? ? ? CancelCallback();
? ? ? ? ? return TimeDelta::Zero(); ?// Ignored.
? ? ? ? } else {
? ? ? ? ? // 如果沒(méi)有幀用于解碼,并且還有時(shí)間
? ? ? ? ? // 這意味著在創(chuàng)建和執(zhí)行此任務(wù)之間清除了幀緩沖區(qū)
? ? ? ? ? // 繼續(xù)等待剩余時(shí)間
? ? ? ? ? int64_t wait_ms = FindNextFrame(clock_->TimeInMilliseconds());
? ? ? ? ? return TimeDelta::ms(wait_ms);
? ? ? ? }
? ? ? });
}
/**
?* 從未解碼的幀 frames_ 中查找 superframe 及其剩余幀,并將其存放到 frames_to_decode_
?* 計(jì)算幀的渲染時(shí)間戳和最大需要等待的時(shí)間
?* 返回等待時(shí)間
*/
int64_t FrameBuffer::FindNextFrame(int64_t now_ms) {
? // 根據(jù)下次返回幀的時(shí)間和當(dāng)前時(shí)間計(jì)算等待時(shí)間
? int64_t wait_ms = latest_return_time_ms_ - now_ms;
? // 清理容器
? frames_to_decode_.clear();
? // 遍歷未解碼的幀 frames_
? for (auto frame_it = frames_.begin();
? ? ? ?frame_it != frames_.end() && frame_it->first <= last_continuous_frame_;
? ? ? ?++frame_it) {
? ? if (!frame_it->second.continuous ||
? ? ? ? frame_it->second.num_missing_decodable > 0) {
? ? ? continue;
? ? }
? ? // 獲取已編碼的幀
? ? EncodedFrame* frame = frame_it->second.frame.get();
? ? // 如果需要關(guān)鍵幀,但當(dāng)前幀不是關(guān)鍵幀,則跳過(guò)
? ? if (keyframe_required_ && !frame->is_keyframe())
? ? ? continue;
? ? // 只會(huì)返回 superframe 的所有部分
? ? // 因此如果不是 superframe 的開(kāi)始,則跳過(guò)
? ? if (frame->inter_layer_predicted) {
? ? ? continue;
? ? }
? ? // 收集同一 superframe 的所有剩余幀?
? ? std::vector<FrameMap::iterator> current_superframe;
? ? current_superframe.push_back(frame_it);
? ? // 判斷下一個(gè)幀是否和當(dāng)前幀為同一 superframe
? ? // 如果是,則將其存放到 current_superframe
? ? bool last_layer_completed = frame_it->second.frame->is_last_spatial_layer;
? ? FrameMap::iterator next_frame_it = frame_it;
? ? // 將同一 superframe 的所有幀存放到 current_superframe
? ? while (true) {
? ? ? ++next_frame_it;
? ? ? if (next_frame_it == frames_.end() ||
? ? ? ? ? next_frame_it->first.picture_id != frame->id.picture_id ||
? ? ? ? ? !next_frame_it->second.continuous) {
? ? ? ? break;
? ? ? }
? ? ? // Check if the next frame has some undecoded references other than
? ? ? // the previous frame in the same superframe.
? ? ? size_t num_allowed_undecoded_refs =
? ? ? ? ? (next_frame_it->second.frame->inter_layer_predicted) ? 1 : 0;
? ? ? if (next_frame_it->second.num_missing_decodable >
? ? ? ? ? num_allowed_undecoded_refs) {
? ? ? ? break;
? ? ? }
? ? ? // All frames in the superframe should have the same timestamp.
? ? ? if (frame->Timestamp() != next_frame_it->second.frame->Timestamp()) {
? ? ? ? RTC_LOG(LS_WARNING) << "Frames in a single superframe have different"
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?" timestamps. Skipping undecodable superframe.";
? ? ? ? break;
? ? ? }
? ? ? current_superframe.push_back(next_frame_it);
? ? ? last_layer_completed = next_frame_it->second.frame->is_last_spatial_layer;
? ? }
? ??
? ? // 檢查當(dāng)前的 superframe 是否完整?
? ? if (!last_layer_completed) {
? ? ? continue;
? ? }
? ? // 將當(dāng)前 superframe 及其剩下的所有幀傳遞給 frames_to_decode_
? ? frames_to_decode_ = std::move(current_superframe);
? ? // 如果幀的渲染時(shí)間戳無(wú)效
? ? // 根據(jù)當(dāng)前時(shí)間和幀的時(shí)間戳計(jì)算幀的渲染時(shí)間戳,并保存到幀信息中
? ? if (frame->RenderTime() == -1) {
? ? ? frame->SetRenderTime(timing_->RenderTimeMs(frame->Timestamp(), now_ms));
? ? }
? ? // 根據(jù)幀的渲染時(shí)間戳和當(dāng)前時(shí)間計(jì)算最大需要等待的時(shí)間
? ? wait_ms = timing_->MaxWaitingTime(frame->RenderTime(), now_ms);
? ? break;
? }
? // 更新等待時(shí)間
? wait_ms = std::min<int64_t>(wait_ms, latest_return_time_ms_ - now_ms);
? wait_ms = std::max<int64_t>(wait_ms, 0);
? return wait_ms;
}
/**
?* 根據(jù)首幀的時(shí)間戳和幀的接收時(shí)間,計(jì)算幀的延遲
?* 根據(jù)幀的延遲和幀的大小,更新抖動(dòng)估計(jì)
?*?
?* 設(shè)置 frames_to_decode_ 中幀的渲染時(shí)間為首幀的渲染時(shí)間
?* 返回待編碼幀 frames_to_decode_
?*?
*/
EncodedFrame* FrameBuffer::GetNextFrame() {
? int64_t now_ms = clock_->TimeInMilliseconds();
? // TODO(ilnik): remove |frames_out| use frames_to_decode_ directly.
? std::vector<EncodedFrame*> frames_out;
? bool superframe_delayed_by_retransmission = false;
? // 統(tǒng)計(jì) superframe 大小,用于更新抖動(dòng)
? size_t superframe_size = 0;
? // 獲取 frames_to_decode_ 中第一個(gè)待解碼的幀
? EncodedFrame* first_frame = frames_to_decode_[0]->second.frame.get();
? // 獲取第一個(gè)待解碼幀的渲染時(shí)間和接收時(shí)間
? int64_t render_time_ms = first_frame->RenderTime();
? int64_t receive_time_ms = first_frame->ReceivedTime();
??
? // 優(yōu)雅地處理壞的RTP時(shí)間戳和渲染時(shí)間問(wèn)題
? if (HasBadRenderTiming(*first_frame, now_ms)) {
? ? jitter_estimator_.Reset();
? ? timing_->Reset();
? ? render_time_ms = timing_->RenderTimeMs(first_frame->Timestamp(), now_ms);
? }
? // 遍歷 frames_to_decode_
? for (FrameMap::iterator& frame_it : frames_to_decode_) {
? ? // 獲取待解碼的幀
? ? EncodedFrame* frame = frame_it->second.frame.release();
? ? // 設(shè)置幀的渲染時(shí)間
? ? frame->SetRenderTime(render_time_ms);
? ? superframe_delayed_by_retransmission |= frame->delayed_by_retransmission();
? ? // 計(jì)算接收時(shí)間
? ? receive_time_ms = std::max(receive_time_ms, frame->ReceivedTime());
? ? // 計(jì)算 superframe 幀大小
? ? superframe_size += frame->size();
? ? PropagateDecodability(frame_it->second);
? ? decoded_frames_history_.InsertDecoded(frame_it->first, frame->Timestamp());
? ? // Remove decoded frame and all undecoded frames before it.
? ? if (stats_callback_) {
? ? ? unsigned int dropped_frames = std::count_if(
? ? ? ? ? frames_.begin(), frame_it,
? ? ? ? ? [](const std::pair<const VideoLayerFrameId, FrameInfo>& frame) {
? ? ? ? ? ? return frame.second.frame != nullptr;
? ? ? ? ? });
? ? ? if (dropped_frames > 0) {
? ? ? ? stats_callback_->OnDroppedFrames(dropped_frames);
? ? ? }
? ? }
? ? frames_.erase(frames_.begin(), ++frame_it);
? ? // 將幀存放到 frames_out
? ? frames_out.push_back(frame);
? }
? if (!superframe_delayed_by_retransmission) {
? ? int64_t frame_delay;
? ? // 根據(jù)首幀的時(shí)間戳和接收時(shí)間 計(jì)算幀延遲并保存到 frame_delay
? ? if (inter_frame_delay_.CalculateDelay(first_frame->Timestamp(),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &frame_delay, receive_time_ms)) {
? ? ? // 根據(jù) 幀延遲 和 superframe 幀大小 更新抖動(dòng)估計(jì)
? ? ? jitter_estimator_.UpdateEstimate(frame_delay, superframe_size);
? ? }
? ? float rtt_mult = protection_mode_ == kProtectionNackFEC ? 0.0 : 1.0;
? ? absl::optional<float> rtt_mult_add_cap_ms = absl::nullopt;
? ? if (rtt_mult_settings_.has_value()) {
? ? ? rtt_mult = rtt_mult_settings_->rtt_mult_setting;
? ? ? rtt_mult_add_cap_ms = rtt_mult_settings_->rtt_mult_add_cap_ms;
? ? }
? ? // 設(shè)置 jitter 延遲
? ? timing_->SetJitterDelay(
? ? ? ? jitter_estimator_.GetJitterEstimate(rtt_mult, rtt_mult_add_cap_ms));
? ? // 更新當(dāng)前延遲
? ? timing_->UpdateCurrentDelay(render_time_ms, now_ms);
? } else {
? ? if (RttMultExperiment::RttMultEnabled() || add_rtt_to_playout_delay_)
? ? ? jitter_estimator_.FrameNacked();
? }
? UpdateJitterDelay();
? UpdateTimingFrameInfo();
? if (frames_out.size() == 1) {
? ? return frames_out[0];
? } else {
? ? return CombineAndDeleteFrames(frames_out);
? }
}
?
總結(jié)
以上是生活随笔為你收集整理的webrtc jitter buffer的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: PLSQL无客户端连接ORACLE
- 下一篇: webrtc jitterbuffer-