摘要:本期就分享幾個關于DVPP視頻解碼問題的典型案例,并給出原因分析及解決方法
本文分享自華為云社區《DVPP媒體資料處理視頻解碼問題案例》,作者:昇騰CANN ,
DVPP(Digital Vision Pre-Processing)是昇騰AI處理器內置的影像處理單元,通過AscendCL媒體資料處理介面提供強大的媒體處理硬加速能力,主要功能包括影像編解碼、視頻編解碼、影像摳圖縮放等,
本期就分享幾個關于DVPP視頻解碼問題的典型案例,并給出原因分析及解決方法:
- 視頻解碼行程卡死,無法退出
- retCode回傳值設定錯誤,導致視頻解碼例外
- 視頻解碼無報錯,但無解碼結果資料,且CPU占用率高
01 視頻解碼行程卡死,無法退出
現象描述
用戶行程卡死,無法退出,查看應用類日志,一直重復提示資訊“fault kernel_name=DvppSendVdecFrame”、“Kernel task happen error, retCode=0x28, [aicpu timeout]”,表示AI CPU例外,無法處理視頻解碼任務,導致任務超時,
日志片段舉例如下:
[ERROR] RUNTIME(pid,pName):DateTimeMS [task.cc:878]1827 PreCheckTaskErr:[DVPP][DEFAULT]Kernel task happen error, retCode=0x28, [aicpu timeout]. [ERROR] RUNTIME(pid,pName):DateTimeMS [task.cc:676]1827 PrintAicpuErrorInfo:[DVPP][DEFAULT]Aicpu kernel execute failed, device_id=0, stream_id=177, task_id=4, fault so_name=libdvpp_kernels.so, fault kernel_name=DvppSendVdecFrame, fault op_name=, extend_info=. [ERROR] RUNTIME(pid,pName):DateTimeMS [task.cc:878]1831 PreCheckTaskErr:[DVPP][DEFAULT]Kernel task happen error, retCode=0x28, [aicpu timeout]. [ERROR] RUNTIME(pid,pName):DateTimeMS [task.cc:676]1831 PrintAicpuErrorInfo:[DVPP][DEFAULT]Aicpu kernel execute failed, device_id=0, stream_id=170, task_id=8, fault so_name=libdvpp_kernels.so, fault kernel_name=DvppSendVdecFrame, fault op_name=, extend_info=. [ERROR] RUNTIME(pid,pName):DateTimeMS [engine.cc:960]1766 ReportExceptProc:[DVPP][DEFAULT]Task exception! device_id=0, stream_id=107, task_id=8, type=1, retCode=0x28. [ERROR] RUNTIME(pid,pName):DateTimeMS [engine.cc:960]1773 ReportExceptProc:[DVPP][DEFAULT]Task exception! device_id=0, stream_id=130, task_id=4, type=1, retCode=0x28.
可能原因
Device記憶體不足,AI CPU無法處理視頻解碼任務,導致任務超時,
處理步驟
1.在使用媒體資料處理V1版本的視頻解碼功能前,可參考性能指標說明頁面中的“每路VDEC解碼的記憶體消耗計算公式”,預估需使用的Device記憶體,并合理規劃Device上的記憶體,
您可以在頁面左上側切換版本,查看對應版本的性能指標說明,
2.優化應用程式的代碼邏輯,增加例外處理機制,獲取視頻解碼例外資訊,強制退出行程,
在呼叫aclinit介面初始化之后、呼叫aclvdecSendFrame介面解碼之前,定義例外回呼函式,并呼叫aclrtSetExceptionInfoCallback介面設定例外回呼函式,用于獲取任務例外資訊,以便在例外分支中根據任務例外資訊來判斷是否退出應用行程,
- 定義例外回呼函式,回呼函式原型為:typedef void (*aclrtExceptionInfoCallback)(aclrtExceptionInfo *exceptionInfo)
- 實作例外回呼函式,在例外回呼函式fn內呼叫aclrtGetDeviceIdFromExceptionInfo、aclrtGetStreamIdFromExceptionInfo、aclrtGetTaskIdFromExceptionInfo介面分別獲取Device ID、Stream ID、Task ID,
根據Stream ID、Task ID判斷Device是否例外,若例外,則強制退出行程,
例外回呼函式實作示例如下:
void dvpp_callback(aclrtExceptionInfo * exception_info) { uint32_t taskId = aclrtGetTaskIdFromExceptionInfo(exception_info); uint32_t streamId = aclrtGetStreamIdFromExceptionInfo(exception_info); uint32_t deviceId = aclrtGetDeviceIdFromExceptionInfo(exception_info); if(taskId == 0xffffffff) || (streamId == 0xffffffff) { //Device例外,強制退出行程 } else { //任務例外,如果頻繁出現(例如,統計1秒內觸發例外回呼函式的次數),行程退出 } return; }
3.呼叫aclrtSetExceptionInfoCallback介面設定例外回呼函式,
02 retCode回傳值設定錯誤,導致視頻解碼例外
現象描述
呼叫aclvdecSendFrame介面發送一幀碼流后,繼續復用輸出圖片描述資訊,進行后續幀碼流的解碼操作,結果反復出現解碼不成功、解碼例外的情況,
日志片段舉例如下:
Channel[0]: success to aclvdecSendFrame, loop=1, count=7 get frame success, totalCount=7 packet.size is 26084. Channel[0]: begin to send frame, loop=1, count=8 acldvppGetPicDescRetCode, retCode: 2. Vdec ERROR!!!!!!!!!!!!!!!! errCount is 3. total count is 3. !!!!!!!!!!!!!!!!!!acldvppGetPicDescRetCode, retCode: 2.right_count:0,fail_count:3,total_count:3 Channel[0]: success to aclvdecSendFrame, loop=1, count=8 get frame success, totalCount=8 packet.size is 27927. Channel[0]: begin to send frame, loop=1, count=9 acldvppGetPicDescRetCode, retCode: 2. Vdec ERROR!!!!!!!!!!!!!!!! errCount is 4. total count is 4. !!!!!!!!!!!!!!!!!!acldvppGetPicDescRetCode, retCode: 2.right_count:0,fail_count:4,total_count:4
可能原因
根據日志中的提示,通過acldvppGetPicDescRetCode介面獲取到的retCode為2,retCode為非0值時,表示解碼例外,
再查看代碼邏輯時,發現由于前一幀碼流解碼失敗,retCode被置為2,在復用輸出圖片描述資訊時,retCode也繼承了前一幀解碼失敗的狀態值2,導致AscendCL在解碼后續幀時,獲取到retCode值為2,就一直判斷解碼是失敗,
處理步驟
如果存在復用輸出圖片描述資訊的場景,需先呼叫acldvppSetPicDescRetCode設定為0,防止前一幀解碼例外的狀態影響后續解碼,
03 視頻解碼無報錯,但無解碼結果資料、CPU占用率高
現象描述
查看應用類日志,無ERROR報錯、無解碼結果資料輸出,另外,在運行應用程式的Linux服務器上執行top命令,該應用行程的CPU占用率持續升高,
可能原因
1. 無ERROR、無解碼結果資料輸出,初步判斷可能是因為解碼發幀介面aclvdecSendFrame呼叫正常,但未觸發回呼函式,無法獲取解碼結果資料,
2. 檢查觸發回呼函式的代碼邏輯,
按照視頻解碼的介面呼叫邏輯:由用戶提前創建一個單獨的執行緒,并自定義執行緒函式,在執行緒函式內呼叫aclrtProcessReport介面,通過該介面配置超時時間,等待指定的超時時間后,觸發回呼函式,獲取解碼結果資料,
Channel[0]: success to aclvdecSendFrame, loop=1, count=7 get frame success, totalCount=7 void *ThreadFunc(aclrtContext sharedContext) { if (sharedContext == nullptr) { ERROR_LOG("sharedContext can not be nullptr"); return ((void*)(-1)); } INFO_LOG("use shared context for this thread"); aclError ret = aclrtSetCurrentContext(sharedContext); if (ret != ACL_SUCCESS) { ERROR_LOG("aclrtSetCurrentContext failed, errorCode = %d", static_cast<int32_t>(ret)); return ((void*)(-1)); } INFO_LOG("thread start "); while (runFlag) { // Notice: timeout 1000ms (void)aclrtProcessReport(1000); } return (void*)0; }
3. 如果觸發回呼函式的介面呼叫邏輯正確,則在aclrtProcessReport介面處增加日志列印,判斷應用運行程序中執行緒是否成功呼叫了aclrtProcessReport介面,只有成功呼叫aclrtProcessReport介面,才會觸發回呼函式,
示例代碼如下:
while (runFlag) { // Notice: timeout 1000ms aclError ret = aclrtProcessReport(1000); printf("aclrtProcessReport failed, ret=%d.\n", ret); }
4. 修改代碼后,重新編譯運行應用,
在終端螢屏重復出現以下列印資訊,表示呼叫aclrtProcessReport介面失敗:
aclrtProcessReport failed, ret = 107012
查閱該介面的回傳值說明,107012表示執行緒未訂閱或重復訂閱,
5. 檢查代碼邏輯,檢查是否呼叫aclvdecSetChannelDescThreadId介面系結用戶新建的執行緒,按照VDEC視頻解碼的介面呼叫邏輯,只有呼叫該介面系結用戶執行緒,才可以觸發呼叫aclrtProcessReport介面,進而觸發回呼函式,
6. 修改代碼后,重新編譯運行應用,視頻解碼正常,正常輸出解碼結果資料,同時CPU占用率下降,
處理步驟
參見視頻解碼的介面呼叫流程頁面或者參考VDEC功能樣例開發視頻解碼功能,您可以在頁面左上側切換版本,查看對應版本的介面呼叫流程,
其中,需關注以下注意點:
- 創建新執行緒,并自定義執行緒函式,在執行緒函式內呼叫aclrtProcessReport介面,等待指定時間后,觸發回呼函式中的回呼函式,
- 需呼叫aclvdecSetChannelDescThreadId介面系結用戶創建的新執行緒,
- 釋放資源時,依次銷毀通道、銷毀通道描述資訊后,才可以銷毀中用戶創建的新執行緒,
04 更多介紹
[1]昇騰檔案中心
[2]昇騰社區在線課程
[3]昇騰論壇
點擊關注,第一時間了解華為云新鮮技術~
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/551940.html
標籤:其他
上一篇:6年測開經驗,從功能測驗到測驗開發,每一步都深思熟慮...
下一篇:返回列表
