直播帶貨平臺開發,實現音影片同步演算法
本文是對音影片同步演算法的總結,以閱讀 ffplay.c 原始碼為基礎,結合各位博主的分析, 逐漸深入理解同步演算法原理, 並根據自身理解, 編寫一套簡易的影片播放器,用於驗證直播帶貨平臺開發的音影片同步演算法。
ffplay簡介
ffplay 是 FFmpeg 提供的開源播放器,基於 FFmpeg 和 SDL 進行影片播放, 是研究影片播放器,音影片同步演算法的很好的示例。 ffplay 原始碼涉及到很多音影片的基本概念, 在基礎理論缺乏的情況下分析起來並不容易,在分析 ffplay 原始碼之前,要對音影片的相關概念有所瞭解,關於音影片的基本知識,在網路上有很多,也可以參考我的其他文章,這些也是我在學習中的經驗總結。
在 ffmpeg4.1.3 中, ffplay 原始碼約 3700 行,非常的小巧,網上關於 ffplay 原理分析的文章也有很多,這裡不再詳細的分析 ffplay 的原始碼, 僅按照自己的理解對音影片同步演算法進行總結, 並基於 ffplay ,自己動手編寫一個簡易影片播放器, 對音影片同步演算法進行驗證。
為什麼要做音影片同步
直播帶貨平臺開發中,如果僅僅是影片按幀率播放,音訊按取樣率播放,二者沒有同步機制,即使一開始音影片是同步的,隨著時間的流逝,音影片會漸漸失去同步,並且不同步的現象會隨著時間會越來越嚴重。這是因為:
一、播放時間難以精確控制
二、異常、誤差會隨時間累積。
所以,必須直播帶貨平臺開發要採用一定的同步策略,不斷對音影片的時間差作校正,使影像顯示與聲音播放總體保持一致。
音影片同步演算法
音影片同步演算法的核心在於準確計算出音訊與影片播放時間的偏差, 再根據這個偏差對雙方進行調整,確保雙方在你追我趕的過程中保持同步。
1. 音影片同步介紹
影片同步到音訊:即以音訊為主時間軸作為同步源
音訊同步到影片:即以影片為主時間軸作為同步源
音訊和影片同步到系統時鐘:即以系統時鐘為主時間軸作為同步源
ffplay 預設採用第一種同步方式,本節主要闡述影片同步到音訊方式。為什麼大多播放器要採用影片同步到音訊呢,因為音訊的取樣率是固定的,若音訊稍有卡頓,都會很明顯的聽出來,反則影片則不如此,雖然表面上說的是 25P (每秒 25 幀),不一定每一幀的間隔就必須精確到 40ms (所以每幀間隔大約 40ms ,事實上,也很難做到精確的 40ms ),即便偶爾影片間隔延時大了點或小了點,人眼也是察覺不出來的,所以影片的幀率可以是動態的,並不是嚴格標準的!
影片同步到音訊,即以音訊作為主時間軸, 儘量不去干擾音訊的播放,音訊採用獨立的執行緒獨自解碼播放 ( 音訊播放的速度在引數設定完畢後是固定的,因此我們也很容易計算音訊播放的時間 ), 在整個過程中,根據影片與音訊時間差,來決策如何改變影片的播放速度,來確保影片與音訊時間差控制在一定範圍內, 當偏移在 -90ms (音訊滯後於影片)到 +20ms (音訊超前影片)之間時,人感覺不到視聽質量的變化,這個區域可以認為是同步區域;當偏移在 -185 到 +90 之外時,音訊和影片會出現嚴重的不同步現象,此區域認為是不同步區域。這裡我們認為偏移 diff 在 ‘± 一個影片幀間隔 ’ 範圍內即認為是同步的,如下圖所示:
2. 音影片時間偏差計算
直播帶貨平臺開發同步系統的關鍵,就在於計算影片與音訊時間偏差diff , 在 ffplay.c 原始碼中,是透過函式 compute_target_delay 實現的,函式原始碼如下:
static double compute_target_delay(double delay, VideoState *is)
{
double sync_threshold, diff = 0;
/* update delay to follow master synchronisation source */
if (get_master_sync_type(is) != AV_SYNC_VIDEO_MASTER) {
/* if video is slave, we try to correct big delays by
duplicating or deleting a frame */
diff = get_clock(&is->vidclk) - get_master_clock(is);
/* skip or repeat frame. We take into account the
delay to compute the threshold. I still don't know
if it is the best guess */
sync_threshold = FFMAX(AV_SYNC_THRESHOLD_MIN, FFMIN(AV_SYNC_THRESHOLD_MAX, delay));
if (!isnan(diff) && fabs(diff) < is->max_frame_duration) {
if (diff <= -sync_threshold)
delay = FFMAX(0, delay + diff);
else if (diff >= sync_threshold && delay > AV_SYNC_FRAMEDUP_THRESHOLD)
delay = delay + diff;
else if (diff >= sync_threshold)
delay = 2 * delay;
}
}
av_log(NULL, AV_LOG_TRACE, "video: delay=%0.3f A-V=%f\n",
delay, -diff);
return delay;
}
根據自身的理解,結合實際測試,得出diff 的計算方法:
當前影片幀pts : frame->pts * av_q2d(video_st->time_base)
當前直播帶貨平臺影片幀至今流逝的時間: 代表當前影片幀從開始顯示到現在的時間, 在ffplay 中函式 get_clock(&is->vidclk) 給出了具體實現,在本次實驗中, 透過 nowtime - last_showtime 來表示流逝的時間, 由於我們是在影片顯示後立即計算 diff , 這個流逝的時間幾乎可以忽略不計,可以使用 0 表示。
音訊幀播放時間 = 音訊長度 / 取樣率
當前音訊幀播放完畢時間= 當前音訊幀的 pts + 當前音訊幀長度 / 取樣率
= af->pts + (double) af->frame->nb_samples / af->frame->sample_rate;
(在計算音訊幀長度時需要考慮取樣率, 通道數, 樣本格式)
音訊緩衝區中未播放資料的時間: 在 ffplay.c 中,採用如下公式來獲取:
set_clock_at(&is->audclk, is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / is->audio_tgt.bytes_per_sec, is->audio_clock_serial, audio_callback_time / 1000000.0);
緩衝區資料總長度 =SDL 的 A , B 緩衝區總長度 + 當前音訊幀尚未複製到 SDL 緩衝區的剩餘長度 aduio_write_buf_size
到這裡,我們就可以計算得到音影片的播放時間偏差diff , 結合上面的偏差圖,我們很容易判斷出是影片落後於音訊,還是音訊落後於影片。
3. 量化影片播放的時間延時
透過第2 步我們已經計算出音影片的時間偏差, 接下來我們就要根據這個偏差來量化影片延時的時間, 來控制下一個影片幀顯示的時間。
我們參考ffplay.c 中的程式碼片段:
last_duration = vp_duration(is, lastvp, vp);
delay = compute_target_delay(last_duration, is);
time= av_gettime_relative()/1000000.0;
if (time < is->frame_timer + delay) {
*remaining_time = FFMIN(is->frame_timer + delay - time, *remaining_time);
goto display;
}
is->frame_timer += delay;
if (delay > 0 && time - is->frame_timer > AV_SYNC_THRESHOLD_MAX)
is->frame_timer = time;
remaining_time 為下一幀播放的延時時間, ffplay.c 藉助 frame_timer += delay 來記錄當前影片累計播放的時間。
frame_timer + delay - av_gettime_relative()/1000000.0 :代表下一影片幀需要延時的時間,這裡需要減去當前時間,是為了得到定時器或 delay 的時間。
另外, 我們約定任意兩個影片幀的間隔至少為 10ms, 所以才有了:
*remaining_time = FFMIN(is->frame_timer + delay - time, *remaining_time);
4. 編寫簡易的影片播放器
ffplay.c 中的同步演算法對於初學者而言理解起來還是有些難度的, 結合自身對 ffplay.c 原始碼的閱讀,以及音影片同步演算法的理解, 對上述同步程式碼進行精簡, 亦能達到音影片同步的效果程式碼片段如下。
if( pm->av_sync_type == AV_SYNC_AUDIO_MASTER){//
master_clock = get_master_clock(pm);
diff = vp->pts - master_clock;
printf("vps:%lf, audioclock:%lf, diff:%lf\n", vp->pts, master_clock, diff);
sync_threshold = (delay > AV_SYNC_THRESHOLD)?delay:AV_SYNC_THRESHOLD;
if( diff <= -sync_threshold){
delay = 0;
}else if( diff >= sync_threshold){
delay *= 2;
}
}
我們直接根據直播帶貨平臺開發的diff 的值來決策下一幀要延時的時間。
————————————————
宣告:本文由雲豹科技轉發自 揮劍踏蒼穹 部落格,如有侵權請聯絡作者刪除
原文連結:https://blog.csdn.net/u011734326/article/details/97137998
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70002045/viewspace-2779779/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 直播帶貨平臺開發流量體現是重中之重!
- 短影片社交平臺開發,短影片直播帶貨,成品原始碼二次開發原始碼
- 直播平臺開發的小店功能強大,如何解決直播帶貨的貨源
- 直播帶貨平臺,仿某寶實現商品上下滑動
- 直播帶貨平臺原始碼,利用ProgressBar實現垂直、水平進度條原始碼
- 如何開發直播平臺,直播平臺開發需要CDN嗎
- 明星直播帶貨的平臺都有哪些功能?
- pygame播放影片並實現音影片同步GAM
- 直播平臺開發,使用swiper實現輪播效果
- 淺談影片直播帶貨app開發的相關細則APP
- 在直播帶貨平臺開發風口下,我們應該如何做?
- 直播平臺原始碼開發,簽到功能的實現原始碼
- 直播平臺開發乾貨分享——標準直播及快、慢直播的特性
- 直播平臺軟體開發,實現自定義標題欄
- 移動短影片直播開發,短影片原始碼搭建社交平臺原生APP原始碼APP
- 影片服務平臺如何解決直播平臺開發中具有挑戰的工作
- 帶貨直播系統,透過主從同步實現讀寫分離主從同步
- 直播帶貨軟體開發過程中,如何實現圖片上傳
- Qt/C++音影片開發80-ffmpeg實現srt推拉流/實時性非常好/音影片同步/支援格式眾多QTC++
- 直播帶貨系統原始碼,實現MYSQL資料庫的主從同步原始碼MySql資料庫主從同步
- 直播帶貨系統是如何實現直播錄屏的
- 想要實現帶貨直播原始碼秒開?先看看這個原始碼
- 直播帶貨原始碼的開發環境原始碼開發環境
- 直播帶貨系統的開發打破原有的直播模式模式
- 美顏SDK的出現給直播和短影片平臺帶來了哪些影響?
- 直播平臺軟體開發,uni-app實現選項卡功能APP
- 直播平臺軟體開發,前端實現登入拼圖驗證前端
- 商家直播帶貨如何選擇平臺,這些平臺各自有什麼優勢?
- 直播帶貨app原始碼,獲取直播影片的第一幀APP原始碼
- 商城APP直播帶貨,原生開發系統功能APP
- 直播電商平臺開發,css實現超出部分顯示省略號,控制文字CSS
- 直播平臺開發,Clip-path實現按鈕流動邊框動畫動畫
- 直播帶貨平臺搭建市場仍處紅利期,如何看待下半場發展
- 乾貨 | 蘇寧影片雲跨平臺播放器開發方案詳解播放器
- 短影片直播APP系統:成品原始碼開發快速搭建部署平臺APP原始碼
- 淺談直播教育平臺開發成本
- 手機直播平臺開發的解析
- 帶貨直播原始碼,淺談直播實現過程和技術原始碼