本文由融云技術(shù)團(tuán)隊(duì)原創(chuàng)投稿,作者是融云WebRTC高級(jí)工程師蘇道,轉(zhuǎn)載請注明出處。
1、引言
在一個(gè)典型的IM應(yīng)用里,使用實(shí)時(shí)音視頻聊天功能時(shí),視頻首幀的顯示,是一項(xiàng)很重要的用戶體驗(yàn)指標(biāo)。
本文主要通過對(duì)WebRTC接收端的音視頻處理過程分析,來了解和優(yōu)化視頻首幀的顯示時(shí)間,并進(jìn)行了總結(jié)和分享。
(本文同步發(fā)布于:http://www.52im.net/thread-3169-1-1.html)
2、什么是WebRTC?
對(duì)于沒接觸過實(shí)時(shí)音視頻技術(shù)的人來說,總是看到別人在提WebRTC,那WebRTC是什么?我們有必要簡單介紹一下。
說到 WebRTC,我們不得不提到 Gobal IP Solutions,簡稱 GIPS。這是一家 1990 年成立于瑞典斯德哥爾摩的 VoIP 軟件開發(fā)商,提供了可以說是世界上最好的語音引擎。相關(guān)介紹詳見《訪談WebRTC標(biāo)準(zhǔn)之父:WebRTC的過去、現(xiàn)在和未來》。
Skype、騰訊 QQ、WebEx、Vidyo 等都使用了它的音頻處理引擎,包含了受專利保護(hù)的回聲消除算法,適應(yīng)網(wǎng)絡(luò)抖動(dòng)和丟包的低延遲算法,以及先進(jìn)的音頻編解碼器。
Google 在 Gtalk 中也使用了 GIPS 的授權(quán)。Google 在 2011 年以6820萬美元收購了 GIPS,并將其源代碼開源,加上在 2010 年收購的 On2 獲取到的 VPx 系列視頻編解碼器(詳見《即時(shí)通訊音視頻開發(fā)(十七):視頻編碼H.264、VP8的前世今生》),WebRTC 開源項(xiàng)目應(yīng)運(yùn)而生,即 GIPS 音視頻引擎 + 替換掉 H.264 的 VPx 視頻編解碼器。
在此之后,Google 又將在 Gtalk 中用于 P2P 打洞的開源項(xiàng)目 libjingle 融合進(jìn)了 WebRTC。目前 WebRTC 提供了包括 Web、iOS、Android、Mac、Windows、Linux 在內(nèi)的所有平臺(tái)支持。
(以上介紹,引用自《了不起的WebRTC:生態(tài)日趨完善,或?qū)?shí)時(shí)音視頻技術(shù)白菜化》)
雖然WebRTC的目標(biāo)是實(shí)現(xiàn)跨平臺(tái)的Web端實(shí)時(shí)音視頻通訊,但因?yàn)楹诵膶哟a的Native、高品質(zhì)和內(nèi)聚性,開發(fā)者很容易進(jìn)行除Web平臺(tái)外的移殖和應(yīng)用。目前為止,WebRTC幾乎是是業(yè)界能免費(fèi)得到的唯一高品質(zhì)實(shí)時(shí)音視頻通訊技術(shù)。
3、流程介紹
一個(gè)典型的實(shí)時(shí)音視頻處理流程大概是這樣:
- 1)發(fā)送端采集音視頻數(shù)據(jù),通過編碼器生成幀數(shù)據(jù);
- 2)這數(shù)據(jù)被打包成 RTP 包,通過 ICE 通道發(fā)送到接收端;
- 3)接收端接收 RTP 包,取出 RTP payload,完成組幀的操作;
- 4)之后音視頻解碼器解碼幀數(shù)據(jù),生成視頻圖像或音頻 PCM 數(shù)據(jù)。
如下圖所示:

本文所涉及的參數(shù)調(diào)整,談?wù)摰牟糠治挥谏蠄D中的第 4 步。
因?yàn)槭墙邮斩耍詴?huì)收到對(duì)方的 Offer 請求。先設(shè)置 SetRemoteDescription 再 SetLocalDescription。
如下圖藍(lán)色部分:
4、參數(shù)調(diào)整
4.1 視頻參數(shù)調(diào)整
當(dāng)收到 Signal 線程 SetRemoteDescription 后,會(huì)在 Worker 線程中創(chuàng)建 VideoReceiveStream 對(duì)象。具體流程為 SetRemoteDescription -> VideoChannel::SetRemoteContent_w 創(chuàng)建 WebRtcVideoReceiveStream。
WebRtcVideoReceiveStream 包含了一個(gè) VideoReceiveStream 類型 stream_ 對(duì)象, 通過 webrtc::VideoReceiveStream* Call::CreateVideoReceiveStream 創(chuàng)建。
創(chuàng)建后立即啟動(dòng) VideoReceiveStream 工作,即調(diào)用 Start() 方法。
此時(shí) VideoReceiveStream 包含一個(gè) RtpVideoStreamReceiver 對(duì)象準(zhǔn)備開始處理 video RTP 包。
接收方創(chuàng)建 createAnswer 后通過 setLocalDescription 設(shè)置 local descritpion。
對(duì)應(yīng)會(huì)在 Worker 線程中 setLocalContent_w 方法中根據(jù) SDP 設(shè)置 channel 的接收參數(shù),最終會(huì)調(diào)用到 WebRtcVideoReceiveStream::SetRecvParameters。
WebRtcVideoReceiveStream::SetRecvParameters 實(shí)現(xiàn)如下:
void WebRtcVideoChannel::WebRtcVideoReceiveStream::SetRecvParameters(
const ChangedRecvParameters& params) {
bool video_needs_recreation = false;
bool flexfec_needs_recreation = false;
if(params.codec_settings) {
ConfigureCodecs(*params.codec_settings);
video_needs_recreation = true;
}
if(params.rtp_header_extensions) {
config_.rtp.extensions = *params.rtp_header_extensions;
flexfec_config_.rtp_header_extensions = *params.rtp_header_extensions;
video_needs_recreation = true;
flexfec_needs_recreation = true;
}
if(params.flexfec_payload_type) {
ConfigureFlexfecCodec(*params.flexfec_payload_type);
flexfec_needs_recreation = true;
}
if(flexfec_needs_recreation) {
RTC_LOG(LS_INFO) << "MaybeRecreateWebRtcFlexfecStream (recv) because of "
"SetRecvParameters";
MaybeRecreateWebRtcFlexfecStream();
}
if(video_needs_recreation) {
RTC_LOG(LS_INFO)
<< "RecreateWebRtcVideoStream (recv) because of SetRecvParameters";
RecreateWebRtcVideoStream();
}
}
根據(jù)上面 SetRecvParameters 代碼,如果 codec_settings 不為空、rtp_header_extensions 不為空、flexfec_payload_type 不為空都會(huì)重啟 VideoReceiveStream。
video_needs_recreation 表示是否要重啟 VideoReceiveStream。
重啟過程為:把先前創(chuàng)建的釋放掉,然后重建新的 VideoReceiveStream。
以 codec_settings 為例:初始 video codec 支持 H264 和 VP8。若對(duì)端只支持 H264,協(xié)商后的 codec 僅支持 H264。SetRecvParameters 中的 codec_settings 為 H264 不空。其實(shí)前后 VideoReceiveStream 的都有 H264 codec,沒有必要重建 VideoReceiveStream。可以通過配置本地支持的 video codec 初始列表和 rtp extensions,從而生成的 local SDP 和 remote SDP 中影響接收參數(shù)部分調(diào)整一致,并且判斷 codec_settings 是否相等。 如果不相等再 video_needs_recreation 為 true。
這樣設(shè)置就會(huì)使 SetRecvParameters 避免觸發(fā)重啟 VideoReceiveStream 邏輯。
在 debug 模式下,修改后,驗(yàn)證沒有 “RecreateWebRtcVideoStream (recv) because of SetRecvParameters” 的打印, 即可證明沒有 VideoReceiveStream 重啟。
4.2 音頻參數(shù)調(diào)整
和上面的視頻調(diào)整類似,音頻也會(huì)有因?yàn)?rtp extensions 不一致導(dǎo)致重新創(chuàng)建 AudioReceiveStream,也是釋放先前的 AudioReceiveStream,再重新創(chuàng)建 AudioReceiveStream。
參考代碼:
bool WebRtcVoiceMediaChannel::SetRecvParameters(
const AudioRecvParameters& params) {
TRACE_EVENT0("webrtc", "WebRtcVoiceMediaChannel::SetRecvParameters");
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
RTC_LOG(LS_INFO) << "WebRtcVoiceMediaChannel::SetRecvParameters: "
<< params.ToString();
// TODO(pthatcher): Refactor this to be more clean now that we have
// all the information at once.
if(!SetRecvCodecs(params.codecs)) {
return false;
}
if(!ValidateRtpExtensions(params.extensions)) {
return false;
}
std::vector<webrtc::RtpExtension> filtered_extensions = FilterRtpExtensions(
params.extensions, webrtc::RtpExtension::IsSupportedForAudio, false);
if(recv_rtp_extensions_ != filtered_extensions) {
recv_rtp_extensions_.swap(filtered_extensions);
for(auto& it : recv_streams_) {
it.second->SetRtpExtensionsAndRecreateStream(recv_rtp_extensions_);
}
}
return true;
}
AudioReceiveStream 的構(gòu)造方法會(huì)啟動(dòng)音頻設(shè)備,即調(diào)用 AudioDeviceModule 的 StartPlayout。
AudioReceiveStream 的析構(gòu)方法會(huì)停止音頻設(shè)備,即調(diào)用 AudioDeviceModule 的 StopPlayout。
因此重啟 AudioReceiveStream 會(huì)觸發(fā)多次 StartPlayout/StopPlayout。
經(jīng)測試,這些不必要的操作會(huì)導(dǎo)致進(jìn)入視頻會(huì)議的房間時(shí),播放的音頻有一小段間斷的情況。
解決方法:同樣是通過配置本地支持的 audio codec 初始列表和 rtp extensions,從而生成的 local SDP 和 remote SDP 中影響接收參數(shù)部分調(diào)整一致,避免 AudioReceiveStream 重啟邏輯。
另外 audio codec 多為 WebRTC 內(nèi)部實(shí)現(xiàn),去掉一些不用的 Audio Codec,可以減小 WebRTC 對(duì)應(yīng)的庫文件。
4.3 音視頻相互影響
WebRTC 內(nèi)部有三個(gè)非常重要的線程:
- 1)woker 線程;
- 2)signal 線程;
- 3)network 線程。
調(diào)用 PeerConnection 的 API 的調(diào)用會(huì)由 signal 線程進(jìn)入到 worker 線程。
worker 線程內(nèi)完成媒體數(shù)據(jù)的處理,network 線程處理網(wǎng)絡(luò)相關(guān)的事務(wù),channel.h 文件中有說明,以 _w 結(jié)尾的方法為 worker 線程的方法,signal 線程的到 worker 線程的調(diào)用是同步操作。
如下面代碼中的 InvokerOnWorker 是同步操作,setLocalContent_w 和 setRemoteContent_w 是 worker 線程中的方法。
bool BaseChannel::SetLocalContent(const MediaContentDescription* content,
SdpType type,
std::string* error_desc) {
TRACE_EVENT0("webrtc", "BaseChannel::SetLocalContent");
returnI nvokeOnWorker<bool>(
RTC_FROM_HERE,
Bind(&BaseChannel::SetLocalContent_w, this, content, type, error_desc));
}
bool BaseChannel::SetRemoteContent(const MediaContentDescription* content,
SdpType type,
std::string* error_desc) {
TRACE_EVENT0("webrtc", "BaseChannel::SetRemoteContent");
return InvokeOnWorker<bool>(
RTC_FROM_HERE,
Bind(&BaseChannel::SetRemoteContent_w, this, content, type, error_desc));
}
setLocalDescription 和 setRemoteDescription 中的 SDP 信息都會(huì)通過 PeerConnection 的 PushdownMediaDescription 方法依次下發(fā)給 audio/video RtpTransceiver 設(shè)置 SDP 信息。
舉例:執(zhí)行 audio 的 SetRemoteContent_w 執(zhí)行很長(比如音頻 AudioDeviceModule 的 InitPlayout 執(zhí)行耗時(shí)), 會(huì)影響后面的 video SetRemoteContent_w 的設(shè)置時(shí)間。
PushdownMediaDescription 代碼:
RTCError PeerConnection::PushdownMediaDescription(
SdpType type,
cricket::ContentSource source) {
const SessionDescriptionInterface* sdesc =
(source == cricket::CS_LOCAL ? local_description()
: remote_description());
RTC_DCHECK(sdesc);
// Push down the new SDP media section for each audio/video transceiver.
for(const auto& transceiver : transceivers_) {
const ContentInfo* content_info =
FindMediaSectionForTransceiver(transceiver, sdesc);
cricket::ChannelInterface* channel = transceiver->internal()->channel();
if(!channel || !content_info || content_info->rejected) {
continue;
}
const MediaContentDescription* content_desc =
content_info->media_description();
if(!content_desc) {
continue;
}
std::string error;
bool success = (source == cricket::CS_LOCAL)
? channel->SetLocalContent(content_desc, type, &error)
: channel->SetRemoteContent(content_desc, type, &error);
if(!success) {
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, error);
}
}
...
}
5、其他影響首幀顯示的問題
5.1 Android圖像寬高16字節(jié)對(duì)齊
AndroidVideoDecoder 是 WebRTC Android 平臺(tái)上的視頻硬解類。AndroidVideoDecoder 利用 MediaCodec API 完成對(duì)硬件解碼器的調(diào)用。
MediaCodec 有已下解碼相關(guān)的 API:
- 1)dequeueInputBuffer:若大于 0,則是返回填充編碼數(shù)據(jù)的緩沖區(qū)的索引,該操作為同步操作;
- 2)getInputBuffer:填充編碼數(shù)據(jù)的 ByteBuffer 數(shù)組,結(jié)合 dequeueInputBuffer 返回值,可獲取一個(gè)可填充編碼數(shù)據(jù)的 ByteBuffer;
- 3)queueInputBuffer:應(yīng)用將編碼數(shù)據(jù)拷貝到 ByteBuffer 后,通過該方法告知 MediaCodec 已經(jīng)填寫的編碼數(shù)據(jù)的緩沖區(qū)索引;
- 4)dequeueOutputBuffer:若大于 0,則是返回填充解碼數(shù)據(jù)的緩沖區(qū)的索引,該操作為同步操作;
- 5)getOutputBuffer:填充解碼數(shù)據(jù)的 ByteBuffer 數(shù)組,結(jié)合 dequeueOutputBuffer 返回值,可獲取一個(gè)可填充解碼數(shù)據(jù)的 ByteBuffer;
- 6)releaseOutputBuffer:告訴編碼器數(shù)據(jù)處理完成,釋放 ByteBuffer 數(shù)據(jù)。
在實(shí)踐當(dāng)中發(fā)現(xiàn),發(fā)送端發(fā)送的視頻寬高需要 16 字節(jié)對(duì)齊,因?yàn)樵谀承?Android 手機(jī)上解碼器需要 16 字節(jié)對(duì)齊。
大致的原理就是:Android 上視頻解碼先是把待解碼的數(shù)據(jù)通過 queueInputBuffer 給到 MediaCodec。然后通過 dequeueOutputBuffer 反復(fù)查看是否有解完的視頻幀。若非 16 字節(jié)對(duì)齊,dequeueOutputBuffer 會(huì)有一次MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED。而不是一上來就能成功解碼一幀。
經(jīng)測試發(fā)現(xiàn):幀寬高非 16 字節(jié)對(duì)齊會(huì)比 16 字節(jié)對(duì)齊的慢 100 ms 左右。
5.2 服務(wù)器需轉(zhuǎn)發(fā)關(guān)鍵幀請求
iOS 移動(dòng)設(shè)備上,WebRTC App應(yīng)用進(jìn)入后臺(tái)后,視頻解碼由 VTDecompressionSessionDecodeFrame 返回 kVTInvalidSessionErr,表示解碼session 無效。從而會(huì)觸發(fā)觀看端的關(guān)鍵幀請求給服務(wù)器。
這里要求服務(wù)器必須轉(zhuǎn)發(fā)接收端發(fā)來的關(guān)鍵幀請求給發(fā)送端。若服務(wù)器沒有轉(zhuǎn)發(fā)關(guān)鍵幀給發(fā)送端,接收端就會(huì)長時(shí)間沒有可以渲染的圖像,從而出現(xiàn)黑屏問題。
這種情況下只能等待發(fā)送端自己生成關(guān)鍵幀,發(fā)送個(gè)接收端,從而使黑屏的接收端恢復(fù)正常。
5.3 WebRTC內(nèi)部的一些丟棄數(shù)據(jù)邏輯舉例
Webrtc從接受報(bào)數(shù)據(jù)到、給到解碼器之間的過程中也會(huì)有很多驗(yàn)證數(shù)據(jù)的正確性。
舉例1:
PacketBuffer 中記錄著當(dāng)前緩存的最小的序號(hào) first_seq_num_(這個(gè)值也是會(huì)被更新的)。 當(dāng) PacketBuffer 中 InsertPacket 時(shí)候,如果即將要插入的 packet 的序號(hào) seq_num 小于 first_seq_num,這個(gè) packet 會(huì)被丟棄掉。如果因此持續(xù)丟棄 packet,就會(huì)有視頻不顯示或卡頓的情況。
舉例2:
正常情況下 FrameBuffer 中幀的 picture id,時(shí)間戳都是一直正增長的。
如果 FrameBuffer 收到 picture_id 比最后解碼幀的 picture id 小時(shí),分兩種情況:
- 1)時(shí)間戳比最后解碼幀的時(shí)間戳大,且是關(guān)鍵幀,就會(huì)保存下來。
- 2)除情況 1 之外的幀都會(huì)丟棄掉。
代碼如下:
auto last_decoded_frame = decoded_frames_history_.GetLastDecodedFrameId();
auto last_decoded_frame_timestamp =
decoded_frames_history_.GetLastDecodedFrameTimestamp();
if(last_decoded_frame && id <= *last_decoded_frame) {
if(AheadOf(frame->Timestamp(), *last_decoded_frame_timestamp) &&
frame->is_keyframe()) {
// If this frame has a newer timestamp but an earlier picture id then we
// assume there has been a jump in the picture id due to some encoder
// reconfiguration or some other reason. Even though this is not according
// to spec we can still continue to decode from this frame if it is a
// keyframe.
RTC_LOG(LS_WARNING)
<< "A jump in picture id was detected, clearing buffer.";
ClearFramesAndHistory();
last_continuous_picture_id = -1;
} else{
RTC_LOG(LS_WARNING) << "Frame with (picture_id:spatial_id) ("
<< id.picture_id << ":"
<< static_cast<int>(id.spatial_layer)
<< ") inserted after frame ("
<< last_decoded_frame->picture_id << ":"
<< static_cast<int>(last_decoded_frame->spatial_layer)
<< ") was handed off for decoding, dropping frame.";
return last_continuous_picture_id;
}
}
因此為了能讓收到了流順利播放,發(fā)送端和中轉(zhuǎn)的服務(wù)端需要確保視頻幀的 picture_id, 時(shí)間戳正確性。
WebRTC 還有其他很多丟幀邏輯,若網(wǎng)絡(luò)正常且有持續(xù)有接收數(shù)據(jù),但是視頻卡頓或黑屏無顯示,多為流本身的問題。
6、本文小結(jié)
本文通過分析 WebRTC 音視頻接收端的處理邏輯,列舉了一些可以優(yōu)化首幀顯示的點(diǎn),比如通過調(diào)整 local SDP 和 remote SDP 中與影響接收端處理的相關(guān)部分,從而避免 Audio/Video ReceiveStream 的重啟。
另外列舉了 Android 解碼器對(duì)視頻寬高的要求、服務(wù)端對(duì)關(guān)鍵幀請求處理、以及 WebRTC 代碼內(nèi)部的一些丟幀邏輯等多個(gè)方面對(duì)視頻顯示的影響。 這些點(diǎn)都提高了融云 SDK 視頻首幀的顯示時(shí)間,改善了用戶體驗(yàn)。
因個(gè)人水平有限,文章內(nèi)容或許存在一定的局限性,歡迎回復(fù)進(jìn)行討論。
附錄1:融云分享的其它文章
《融云技術(shù)分享:融云安卓端IM產(chǎn)品的網(wǎng)絡(luò)鏈路保活技術(shù)實(shí)踐》
《IM消息ID技術(shù)專題(三):解密融云IM產(chǎn)品的聊天消息ID生成策略》
《融云技術(shù)分享:基于WebRTC的實(shí)時(shí)音視頻首幀顯示時(shí)間優(yōu)化實(shí)踐》(* 本文)
《即時(shí)通訊云融云CTO的創(chuàng)業(yè)經(jīng)驗(yàn)分享:技術(shù)創(chuàng)業(yè),你真的準(zhǔn)備好了?》
附錄2:更多實(shí)時(shí)音視頻相關(guān)技術(shù)文章
[1] 開源實(shí)時(shí)音視頻技術(shù)WebRTC的文章:
《開源實(shí)時(shí)音視頻技術(shù)WebRTC的現(xiàn)狀》
《簡述開源實(shí)時(shí)音視頻技術(shù)WebRTC的優(yōu)缺點(diǎn)》
《訪談WebRTC標(biāo)準(zhǔn)之父:WebRTC的過去、現(xiàn)在和未來》
《良心分享:WebRTC 零基礎(chǔ)開發(fā)者教程(中文)[附件下載]》
《WebRTC實(shí)時(shí)音視頻技術(shù)的整體架構(gòu)介紹》
《新手入門:到底什么是WebRTC服務(wù)器,以及它是如何聯(lián)接通話的?》
《WebRTC實(shí)時(shí)音視頻技術(shù)基礎(chǔ):基本架構(gòu)和協(xié)議棧》
《淺談開發(fā)實(shí)時(shí)視頻直播平臺(tái)的技術(shù)要點(diǎn)》
《[觀點(diǎn)] WebRTC應(yīng)該選擇H.264視頻編碼的四大理由》
《基于開源WebRTC開發(fā)實(shí)時(shí)音視頻靠譜嗎?第3方SDK有哪些?》
《開源實(shí)時(shí)音視頻技術(shù)WebRTC中RTP/RTCP數(shù)據(jù)傳輸協(xié)議的應(yīng)用》
《簡述實(shí)時(shí)音視頻聊天中端到端加密(E2EE)的工作原理》
《實(shí)時(shí)通信RTC技術(shù)棧之:視頻編解碼》
《開源實(shí)時(shí)音視頻技術(shù)WebRTC在Windows下的簡明編譯教程》
《網(wǎng)頁端實(shí)時(shí)音視頻技術(shù)WebRTC:看起來很美,但離生產(chǎn)應(yīng)用還有多少坑要填?》
《了不起的WebRTC:生態(tài)日趨完善,或?qū)?shí)時(shí)音視頻技術(shù)白菜化》
《騰訊技術(shù)分享:微信小程序音視頻與WebRTC互通的技術(shù)思路和實(shí)踐》
《融云技術(shù)分享:基于WebRTC的實(shí)時(shí)音視頻首幀顯示時(shí)間優(yōu)化實(shí)踐》
>> 更多同類文章 ……
[2] 實(shí)時(shí)音視頻開發(fā)的其它精華資料:
《即時(shí)通訊音視頻開發(fā)(一):視頻編解碼之理論概述》
《即時(shí)通訊音視頻開發(fā)(二):視頻編解碼之?dāng)?shù)字視頻介紹》
《即時(shí)通訊音視頻開發(fā)(三):視頻編解碼之編碼基礎(chǔ)》
《即時(shí)通訊音視頻開發(fā)(四):視頻編解碼之預(yù)測技術(shù)介紹》
《即時(shí)通訊音視頻開發(fā)(五):認(rèn)識(shí)主流視頻編碼技術(shù)H.264》
《即時(shí)通訊音視頻開發(fā)(六):如何開始音頻編解碼技術(shù)的學(xué)習(xí)》
《即時(shí)通訊音視頻開發(fā)(七):音頻基礎(chǔ)及編碼原理入門》
《即時(shí)通訊音視頻開發(fā)(八):常見的實(shí)時(shí)語音通訊編碼標(biāo)準(zhǔn)》
《即時(shí)通訊音視頻開發(fā)(九):實(shí)時(shí)語音通訊的回音及回音消除概述》
《即時(shí)通訊音視頻開發(fā)(十):實(shí)時(shí)語音通訊的回音消除技術(shù)詳解》
《即時(shí)通訊音視頻開發(fā)(十一):實(shí)時(shí)語音通訊丟包補(bǔ)償技術(shù)詳解》
《即時(shí)通訊音視頻開發(fā)(十二):多人實(shí)時(shí)音視頻聊天架構(gòu)探討》
《即時(shí)通訊音視頻開發(fā)(十三):實(shí)時(shí)視頻編碼H.264的特點(diǎn)與優(yōu)勢》
《即時(shí)通訊音視頻開發(fā)(十四):實(shí)時(shí)音視頻數(shù)據(jù)傳輸協(xié)議介紹》
《即時(shí)通訊音視頻開發(fā)(十五):聊聊P2P與實(shí)時(shí)音視頻的應(yīng)用情況》
《即時(shí)通訊音視頻開發(fā)(十六):移動(dòng)端實(shí)時(shí)音視頻開發(fā)的幾個(gè)建議》
《即時(shí)通訊音視頻開發(fā)(十七):視頻編碼H.264、VP8的前世今生》
《即時(shí)通訊音視頻開發(fā)(十八):詳解音頻編解碼的原理、演進(jìn)和應(yīng)用選型》
《即時(shí)通訊音視頻開發(fā)(十九):零基礎(chǔ),史上最通俗視頻編碼技術(shù)入門》
《實(shí)時(shí)語音聊天中的音頻處理與編碼壓縮技術(shù)簡述》
《網(wǎng)易視頻云技術(shù)分享:音頻處理與壓縮技術(shù)快速入門》
《學(xué)習(xí)RFC3550:RTP/RTCP實(shí)時(shí)傳輸協(xié)議基礎(chǔ)知識(shí)》
《基于RTMP數(shù)據(jù)傳輸協(xié)議的實(shí)時(shí)流媒體技術(shù)研究(論文全文)》
《聲網(wǎng)架構(gòu)師談實(shí)時(shí)音視頻云的實(shí)現(xiàn)難點(diǎn)(視頻采訪)》
《淺談開發(fā)實(shí)時(shí)視頻直播平臺(tái)的技術(shù)要點(diǎn)》
《還在靠“喂喂喂”測試實(shí)時(shí)語音通話質(zhì)量?本文教你科學(xué)的評(píng)測方法!》
《實(shí)現(xiàn)延遲低于500毫秒的1080P實(shí)時(shí)音視頻直播的實(shí)踐分享》
《移動(dòng)端實(shí)時(shí)視頻直播技術(shù)實(shí)踐:如何做到實(shí)時(shí)秒開、流暢不卡》
《如何用最簡單的方法測試你的實(shí)時(shí)音視頻方案》
《技術(shù)揭秘:支持百萬級(jí)粉絲互動(dòng)的Facebook實(shí)時(shí)視頻直播》
《簡述實(shí)時(shí)音視頻聊天中端到端加密(E2EE)的工作原理》
《移動(dòng)端實(shí)時(shí)音視頻直播技術(shù)詳解(一):開篇》
《移動(dòng)端實(shí)時(shí)音視頻直播技術(shù)詳解(二):采集》
《移動(dòng)端實(shí)時(shí)音視頻直播技術(shù)詳解(三):處理》
《移動(dòng)端實(shí)時(shí)音視頻直播技術(shù)詳解(四):編碼和封裝》
《移動(dòng)端實(shí)時(shí)音視頻直播技術(shù)詳解(五):推流和傳輸》
《移動(dòng)端實(shí)時(shí)音視頻直播技術(shù)詳解(六):延遲優(yōu)化》
《理論聯(lián)系實(shí)際:實(shí)現(xiàn)一個(gè)簡單地基于HTML5的實(shí)時(shí)視頻直播》
《IM實(shí)時(shí)音視頻聊天時(shí)的回聲消除技術(shù)詳解》
《淺談實(shí)時(shí)音視頻直播中直接影響用戶體驗(yàn)的幾項(xiàng)關(guān)鍵技術(shù)指標(biāo)》
《如何優(yōu)化傳輸機(jī)制來實(shí)現(xiàn)實(shí)時(shí)音視頻的超低延遲?》
《首次披露:快手是如何做到百萬觀眾同場看直播仍能秒開且不卡頓的?》
《Android直播入門實(shí)踐:動(dòng)手搭建一套簡單的直播系統(tǒng)》
《網(wǎng)易云信實(shí)時(shí)視頻直播在TCP數(shù)據(jù)傳輸層的一些優(yōu)化思路》
《實(shí)時(shí)音視頻聊天技術(shù)分享:面向不可靠網(wǎng)絡(luò)的抗丟包編解碼器》
《P2P技術(shù)如何將實(shí)時(shí)視頻直播帶寬降低75%?》
《專訪微信視頻技術(shù)負(fù)責(zé)人:微信實(shí)時(shí)視頻聊天技術(shù)的演進(jìn)》
《騰訊音視頻實(shí)驗(yàn)室:使用AI黑科技實(shí)現(xiàn)超低碼率的高清實(shí)時(shí)視頻聊天》
《微信團(tuán)隊(duì)分享:微信每日億次實(shí)時(shí)音視頻聊天背后的技術(shù)解密》
《近期大熱的實(shí)時(shí)直播答題系統(tǒng)的實(shí)現(xiàn)思路與技術(shù)難點(diǎn)分享》
《福利貼:最全實(shí)時(shí)音視頻開發(fā)要用到的開源工程匯總》
《七牛云技術(shù)分享:使用QUIC協(xié)議實(shí)現(xiàn)實(shí)時(shí)視頻直播0卡頓!》
《實(shí)時(shí)音視頻聊天中超低延遲架構(gòu)的思考與技術(shù)實(shí)踐》
《理解實(shí)時(shí)音視頻聊天中的延時(shí)問題一篇就夠》
《實(shí)時(shí)視頻直播客戶端技術(shù)盤點(diǎn):Native、HTML5、WebRTC、微信小程序》
《寫給小白的實(shí)時(shí)音視頻技術(shù)入門提綱》
《微信多媒體團(tuán)隊(duì)訪談:音視頻開發(fā)的學(xué)習(xí)、微信的音視頻技術(shù)和挑戰(zhàn)等》
《騰訊技術(shù)分享:微信小程序音視頻技術(shù)背后的故事》
《微信多媒體團(tuán)隊(duì)梁俊斌訪談:聊一聊我所了解的音視頻技術(shù)》
《新浪微博技術(shù)分享:微博短視頻服務(wù)的優(yōu)化實(shí)踐之路》
《實(shí)時(shí)音頻的混音在視頻直播應(yīng)用中的技術(shù)原理和實(shí)踐總結(jié)》
《以網(wǎng)游服務(wù)端的網(wǎng)絡(luò)接入層設(shè)計(jì)為例,理解實(shí)時(shí)通信的技術(shù)挑戰(zhàn)》
《騰訊技術(shù)分享:微信小程序音視頻與WebRTC互通的技術(shù)思路和實(shí)踐》
《新浪微博技術(shù)分享:微博實(shí)時(shí)直播答題的百萬高并發(fā)架構(gòu)實(shí)踐》
《技術(shù)干貨:實(shí)時(shí)視頻直播首屏耗時(shí)400ms內(nèi)的優(yōu)化實(shí)踐》
《愛奇藝技術(shù)分享:輕松詼諧,講解視頻編解碼技術(shù)的過去、現(xiàn)在和將來》
《零基礎(chǔ)入門:實(shí)時(shí)音視頻技術(shù)基礎(chǔ)知識(shí)全面盤點(diǎn)》
>> 更多同類文章 ……
本文已同步發(fā)布于“即時(shí)通訊技術(shù)圈”公眾號(hào):

本文在公眾號(hào)上的鏈接是:點(diǎn)此進(jìn)入,原文鏈接是:http://www.52im.net/thread-3169-1-1.html