Twitch如何实现转码比FFmpeg性能提升65%?(下)
文 / Jeff Gong, Sahil Dhanju, Chih-Chiang Lu, Yueshi Shen
編者按:超過220萬創(chuàng)作者在Twitch發(fā)布海量的視頻,這對實時轉(zhuǎn)碼業(yè)務造成了巨大壓力,Twitch團隊通過優(yōu)化多線程的轉(zhuǎn)碼服務以及Intel QuickSync的支持,實現(xiàn)了比FFmepg性能提升65%,并降低80%總體擁有成本。Twitch團隊通過博客介紹了這一實現(xiàn),LiveVideoStack對本文進行了摘譯,點擊『閱讀原文』訪問英文博客。同時,Yueshi Shen將在12月8-9日的ArchSummit 2017北京大會上詳細介紹實現(xiàn)過程。
FFmpeg的1-in-N-out流水線。為什么它無法處理前面討論的技術(shù)問題?
FFmpeg如何以編程方式處理需要單個輸入來生成多個轉(zhuǎn)碼和(或)轉(zhuǎn)封裝輸出的實例? 我們可以通過直接剖析FFmpeg最新3.3版的源代碼,來了解其線程模型和轉(zhuǎn)碼流水線。
在頂層ffmpeg.c文件中,transcode()函數(shù)(第4544行)不斷循環(huán)并重復調(diào)用transcode_step()函數(shù)(第4478行),直到其輸入信息被完全處理,或用戶中斷執(zhí)行為止。Transcode_step()函數(shù)封裝了主要的流水線,并在許多其他即時步驟之間編排諸如文件I / O、過濾、解碼和編碼等動作。
在初始設置階段,init_input_threads()(第4020行)函數(shù)被調(diào)用,并將根據(jù)輸入文件的數(shù)量,產(chǎn)生一些新的線程來處理這些輸入。
if (nb_input_files == 1) {
?return 0;
}
for (i = 0; i < nb_input_files; i++) {
?...
?ret = av_thread_message_queue_alloc(&f->in_thread_queue, f->thread_queue_size, sizeof(AVPacket)); ? ?// line 4033
}
在第4033行中(如上所示),我們看到產(chǎn)生的線程數(shù)量完全由輸入的數(shù)量決定。也就是說,這意味著FFmpeg將只使用一個線程來處理1-in-N-out的場景。
在get_input_packet()函數(shù)(第4055行)中,只有當輸入文件的數(shù)量大于1時,才會調(diào)用多線程伴隨函數(shù)get_input_packet_mt()(第4047行)。get_input_packet_mt()函數(shù)可以以非阻塞的方式從消息隊列中讀取輸入幀。否則的話,我們需要使用av_read_frame()(第4072行)來每次讀取并處理一個幀。
?if (nb_input_files > 1) {
? ? get_input_packet_mt(f, pkt);
?}
?return av_read_frame(f->ctx, pkt);
如果我們跟蹤幀數(shù)據(jù)一直到流水線結(jié)束,我們發(fā)現(xiàn)它進入到process_input_packet()函數(shù)(行2591)中,該函數(shù)對幀數(shù)據(jù)進行解碼并通過所有適用的過濾器進行處理。時間戳校準和字幕處理的工作也在這個函數(shù)中進行。最后,在函數(shù)返回之前,已解碼的幀被復制到每個相關(guān)的輸出流。
for (i = 0; pkt && i < nb_output_streams; i++) {
?... ?// check constraints
?do_streamcopy(ist, ost, pkt); ? ?// line 2756
}
最后,transcode_step()函數(shù)調(diào)用reap_filters()函數(shù)(第1424行)來循環(huán)遍歷每個輸出流。reap_filters()函數(shù)的for循環(huán)負責收集緩沖區(qū)中待處理的幀,并將這些幀進行解碼,然后封裝到一個輸出文件中。
// reap_filters line 1423
for (i = 0; i < nb_output_streams; i++) { // loop through all output streams
?... ?// initialize contexts and files
?OutputStream *ost = output_streams[i];
?AVFilterContext *filter = ost->filter->filter;
?AVFrame filtered_frame = ost->filtered_frame;
?while (1) { // process the video/audio frame for one output stream
? ? ... ?// frame is not already complete
? ? ret = av_buffersink_get_frame_flags(filter, filtered_frame, …);
? ? if (ret < 0) {
? ? ? ?... ?// handle errors and logs
? ? ? ?break;
? ? }
? ? switch (av_buffersink_get_type(filter)) {
? ? case AVMEDIA_TYPE_VIDEO:
? ? ? ?do_video_out(of, ost, filtered_frame, float_pts);
? ? case AVMEDIA_TYPE_AUDIO:
? ? ? ?do_audio_out(of, ost, filtered_frame);
? ? }
? ? ...
}
通過跟蹤這條流水線,我們知道這些幀是如何通過單個線程的上下文順序進行處理的,從中我們能看到一些冗余。我們可以得出結(jié)論,既然1-in-N-out的轉(zhuǎn)碼流模型對我們來說是最有價值的,那么FFmpeg僅使用單線程來輸出結(jié)果則可能并不理想。FFmpeg文檔也建議我們在實際用例中,并行地啟動多個FFmpeg實例或?qū)⒏幸饬x。在這里,我們關(guān)鍵的一點認識是,既然此工具(FFmpeg)沒有提供多線程功能,它就無法滿足Twitch流媒體服務的嚴格需求,那么我們就無法隨心所欲地使用它。
基準測試
TwitchTranscoder是我們?yōu)榻鉀Q前面討論的技術(shù)問題而開發(fā)的內(nèi)部軟件。它已被廣泛運用于我們的生產(chǎn)中,每天24小時地處理數(shù)萬個并發(fā)直播流。
為了確定TwitchTranscoder每天在轉(zhuǎn)碼任務上的表現(xiàn)是否會優(yōu)于FFmpeg,我們進行了一系列基本的基準測試。在我們的測試中,我們對兩個工具使用相同的Twitch直播流以及有相同預設、配置文件、比特率和其他標志的1080p60視頻文件。每個視頻源都被轉(zhuǎn)碼成我們通常使用的典型的720p60,720p30,480p30,360p30和160p30。
我們的假設是,FFmpeg對于輸入文件的轉(zhuǎn)碼速度比TwitchTranscoder要慢,甚至可能無法跟上直播的速度。
圖9,10和11中的結(jié)果比較了TwitchTranscoder與FFmpeg的執(zhí)行時間。實驗表明,即使在我們處理相同及更多(除了上面指定的棧之外,還提供僅音頻轉(zhuǎn)碼,縮略圖生成等等)任務的情況下,我們的轉(zhuǎn)碼器對于離線轉(zhuǎn)碼一直有絕對優(yōu)勢。
對于輸出單個版本的720p60,FFmpeg稍快,這是因為TwitchTranscoder要處理如上所述的更多任務。當版本的數(shù)量增加時,TwitchTranscoder的多線程模型表現(xiàn)出更大的優(yōu)勢,這些優(yōu)勢幫助它超越了FFmpeg。觀察Twitch完整的ABR梯度,與FFmpeg相比,TwitchTranscoder節(jié)省了65%的執(zhí)行時間。
圖9:TwitchTranscoder與FFmpeg轉(zhuǎn)碼時間比較,實驗1
圖10:TwitchTranscoder與FFmpeg轉(zhuǎn)碼時間比較,實驗2
圖11:TwitchTranscoder與FFmpeg轉(zhuǎn)碼時間比較,實驗2
我們通過比較在出問題前,一臺機器上最多能夠運行多少個FFmpeg的并行實例來進行實時流轉(zhuǎn)碼測試。這里可能發(fā)生的問題包括幀丟失、視頻偽影等。在我們的生產(chǎn)服務器中,我們能夠支持多個通道同時進行轉(zhuǎn)碼,同時,更多的通道被轉(zhuǎn)封裝。不幸的是,運行多個FFmpeg實例會導致一系列影響轉(zhuǎn)碼輸出的錯誤,并且需要更高的CPU利用率(請參見圖12中的屏幕截圖)。
圖12:FFmpeg運行多個實例時的錯誤消息
結(jié)論
在本文中,我們將FFmpeg作為實時流RTMP- to-HLS的轉(zhuǎn)碼器進行了研究,并提供了有關(guān)如何操作該工具的信息。該解決方案部署起來很簡單,但有一些技術(shù)問題值得注意,比如段錯位、不必要的性能損失,以及缺乏支持我們產(chǎn)品功能的靈活性等。因此,我們實現(xiàn)了自己內(nèi)部的轉(zhuǎn)碼器軟件棧TwitchTranscoder,它運行在一個定制的線程模型中,并可以在一個進程中輸出N個處理版本。
LiveVideoStack招募全職技術(shù)編輯和社區(qū)編輯
LiveVideoStack是專注在音視頻、多媒體開發(fā)的技術(shù)社區(qū),通過傳播最新技術(shù)探索與應用實踐,幫助技術(shù)人員成長,解決企業(yè)應用場景中的技術(shù)難題。如果你有意為音視頻、多媒體開發(fā)領(lǐng)域發(fā)展做出貢獻,歡迎成為LiveVideoStack社區(qū)編輯的一員。你可以翻譯、投稿、采訪、提供內(nèi)容線索等。
通過contribute@livevideostack.com聯(lián)系,或在LiveVideoStack公眾號回復『技術(shù)編輯』或『社區(qū)編輯』了解詳情。
總結(jié)
以上是生活随笔為你收集整理的Twitch如何实现转码比FFmpeg性能提升65%?(下)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Twitch如何实现转码器比FFmepg
- 下一篇: 语音视频社交背后技术深度解析