本文檔詳細介紹TUTK P2P SDK中APP端傳輸狀況估算及丟幀判斷的實現(xiàn)方法,包括設備端發(fā)送FPS計算、網(wǎng)絡波動識別、丟幀分析邏輯,適用于音視頻傳輸場景的網(wǎng)絡狀態(tài)監(jiān)測。
一、APP端傳輸狀況估算與丟幀判斷方法
目前 APP 端暫無直接反饋傳輸狀況的接口,但可通過間接方法估算:通過接收端實際 FPS 與設備端理論發(fā)送 FPS 對比,判斷網(wǎng)絡波動;通過幀時間戳差值分析,判斷是否存在丟幀。以下為具體實現(xiàn)方案:
1. 計算設備端發(fā)送FPS(理論值)
核心邏輯:基于設備端傳輸?shù)膸瑫r間戳(單位:ms),計算連續(xù)幀的時間戳差值平均值,進而推導理論發(fā)送 FPS。建議統(tǒng)計 10 次時間戳差值,去除極值后計算平均值,結(jié)果更準確。
/*
* 此用例用以演示如何估算設備端的發(fā)送fps。
* 此計算用例中,設備端傳過來的時間戳以ms為單位。
* 計算10次
*/
#define MAX_CAL_COUNT 10
unsigned int last_ts = 0;//用以存放上次的時間戳
bool need_cal_send_fps = true;
int ts_tmp[MAX_CAL_COUNT] = {0};//用以存放時間戳差值
int ts_tmp_arr_index = 0;
int fps;
while(1){
int ret = avRecvFrameData2(avIndex, buf, video_buf_size, &outBufSize, &outFrmSize, (char *)&frameInfo, sizeof(FRAMEINFO_t), &outFrmInfoSize, &frmNo);
if(ret > 0){
if(need_cal_send_fps && ts_tmp_arr_index < MAX_CAL_COUNT){
if(last_ts){
int ts_from_last = frameInfo.timestamp - last_ts; //與上一幀的時間戳差值
if(ts_from_last > 0){
ts_tmp[ts_tmp_arr_index++] = ts_from_last;
}
if(ts_tmp_arr_index == MAX_CAL_COUNT){
//計算時間戳差值的平均值,可以去掉一個最高,一個最低再算。
int ts = average(ts_tmp, MAX_CAL_COUNT);
fps = 1000 / ts; //此為設備端理論的發(fā)送fps
}
}
else{
last_ts = frameInfo.timestamp;
}
}
}
}
示例計算:若 10 次時間戳差值為 ts_tmp[10] = {40,40,80,40,40,40,40,40,40,35},去除一個最大值(80)和一個最小值(35)后,剩余 8 次差值均為 40ms,平均值為 40ms,則理論發(fā)送 FPS = 1000 / 40 = 25。
網(wǎng)絡波動判斷:APP 端統(tǒng)計接收端實際 FPS(recv_fps),持續(xù)對比 3-5 秒。正常情況下 recv_fps 應穩(wěn)定在理論發(fā)送 FPS 附近;若兩者差距過大或 FPS 暴增暴減,說明網(wǎng)絡波動較大。
2. 丟幀判斷方法
核心說明:開啟重傳后通常不會丟幀,但設備端調(diào)用 avSendFrameData 接口返回 AV_ER_EXCEED_MAX_SIZE(-20006) 時,該幀會被 SDK 丟棄(未進入緩存區(qū))。由于 SDK 僅對緩存區(qū)的幀進行編號,APP 端拿到的幀號(frmNo)仍會連續(xù),無法通過幀號判斷丟幀,需通過時間戳差值分析。
/*
* 先計算前后時間戳理論差值(aver_ts_from_last)
* 再根據(jù)當前差值跟理論差值的差距判斷是否丟幀
*/
unsigned int last_ts = 0;//用以存放上次的時間戳
int aver_ts_from_last = 0;//用以存放時間戳差值的平均值,計算方法參考上文
while(1){
int ret = avRecvFrameData2(avIndex, buf, video_buf_size, &outBufSize, &outFrmSize, (char *)&frameInfo, sizeof(FRAMEINFO_t), &outFrmInfoSize, &frmNo);
if(ret > 0){
if(last_ts){
int ts_from_last = frameInfo.timestamp - last_ts; //與上一幀的時間戳差值
if(ts_from_last > 1.5 * aver_ts_from_last){
printf("video maybe lost...\n");
}
}
else{
last_ts = frameInfo.timestamp;
continue;
}
last_ts = frameInfo.timestamp;
}
}
說明:示例中通過時間戳差值的倍數(shù)閾值判斷丟幀,可根據(jù)實際業(yè)務場景調(diào)整閾值(如2倍),平衡檢測靈敏度與誤判率;建議結(jié)合滑動窗口算法統(tǒng)計實際FPS,減少瞬時波動影響。
判斷邏輯:若當前幀與上一幀的時間戳差值(ts_from_last)超過理論平均差值(aver_ts_from_last)的 1.5 倍,則判定為該幀前存在丟幀。可根據(jù)實際業(yè)務場景調(diào)整閾值(如 2 倍),平衡靈敏度與誤判率。