关于IMX6Dl 芯片使用硬编解码的问题记录
NXP出了IMX6系列芯片(現在應該是9系列最新了),性能相當于我們嵌入式行業,已經非常優秀(可以做很多事情)
同時,IMX6DL IMX6Q 自帶vpu硬編解碼,用來處理下視頻也是非常不錯的,對于我們來說的確非常合適
眾所周知,mxc_vpu_test.out 是官方提供的測試程序,用于測試各種功能,源碼也提供,
但是系統里面源碼是跟其他測試程序整合在一起的,往往我們想要在此基礎上改改弄弄,然后重新編譯是件困難的事情(大神除外)
當然,也可以從網上下載?mxc_vpu_test.out 的源碼,貌似也有(csdn就有),但可能跟你板子的庫文件版本不一致,會導致各種問題
總之這是一個繞不過去的坑(編譯過不算,正常運行編解碼才算)
以上問題,困擾很久,后來版本搞對了,才算順利過去。 ---- 記一下,如果用測試程序 編譯沒有問題,但測試解碼時候,出現段錯誤,往往是你所用h文件跟板子so庫用的h文件版本不一樣,也就是某些結構體size不一樣。
另外一個問題:
假設在同一塊板子上,先采集USB攝像頭的數據,然后vpu編碼產生h264流,然后通過“管道”發送給解碼線程,解碼線程收到h264流,然后調用vpu的解碼,然后再顯示。當然這個步驟是異步的,兩個線程(進程),中間涉及到數據交互的。
源代碼是參考?mxc_vpu_test.out 的源碼
ps: 說到這里,可能有些人會說,既然是一塊板子,那么直接顯示USB攝像頭上的數據,不是更好的?嗯,我舉的例子,的確這樣做更好,但不要忘記現實的項目可能是這樣的需求:在本終端上顯示的畫面是其他終端傳過來的h264數據,而本終端需要將自己的視頻流傳輸給對方(就好比視頻對講),這樣就需要一臺板子上同時編解碼(當然此時用的通道肯定是兩個)
?
貌似應該沒有問題,也說得通,只要編解碼本身沒有問題,那么問題就沒有。但現實往往是骨感的,的確是碰到問題
一開始懷疑管道寫錯了,但管道的確沒有問題
通過步驟printf 的方式,發現卡在:
?
也就是說 開始編碼的時候,就不再返回。
分析了dec.c 的源碼:
dec這邊最后一步是出現這里:
?
dec_fill_bsbuffer 實際上是去讀取管道數據(由于是阻塞式管道,不阻塞不行,不阻塞的話,這里返回是0,那么dec這邊會認為“沒有數據” 自然退出)。此時卡住了。
原因:
解碼這邊,在讀取管道數據之前,先調用?vpu_DecStartOneFrame ,這個函數會占據vpu資源,
導致解碼那邊調用 vpu_EncStartOneFrame 函數卡死(因為獲取不到vpu資源,從而也沒有往下走)
這樣就形成了“死鎖”,編碼這邊等待vpu資源釋放(才能有數據往管道里放),解碼這邊等待管道里有數據(才能完成解碼,從而才能釋放vpu資源)
也許,把?vpu_DecStartOneFrame 放在?dec_fill_bsbuffer 之后,是否可行?也不行,只是概率問題。
從現象來看,我們也知道同一塊板子如果同時?vpu_DecStartOneFrame?vpu_EncStartOneFrame是不行的
當然唯一的辦法就是錯時。
我的辦法也很簡單,利用一個緩沖,錯時,如果緩沖里沒有數據,解碼這邊就不調用?vpu_DecStartOneFrame,線程等待就好了。
當然這個緩沖也有點小復雜,不是簡簡單單加個鎖就行了,還是要考慮到各種情況的。
下面亮出我的代碼:
1 static char *m_pPipeBuf = NULL;2 static int m_nNowPos = 0;3 static int m_nGetPos = 0;4 static pthread_mutex_t m_lock;5 6 //建立緩存區7 void Safe_InitBuff()8 {9 if(m_pPipeBuf != NULL)10 Safe_UnInitBuff();11 12 pthread_mutex_init(&m_lock,NULL);13 m_pPipeBuf = (char*)malloc(PIPE_LENTH + 1024);14 m_nNowPos = 0;15 m_nGetPos = 0;16 }17 18 void Safe_UnInitBuff()19 {20 if(m_pPipeBuf != NULL)21 {22 free(m_pPipeBuf);23 m_pPipeBuf = NULL;24 25 pthread_mutex_destroy(&m_lock);26 m_nNowPos = 0;27 m_nGetPos = 0;28 }29 }30 31 //剩余可以存放 多少空間32 static int GetLastTemp()33 {34 int nLast = 0;35 36 if(m_nNowPos >= m_nGetPos)37 {38 nLast = PIPE_LENTH - (m_nNowPos - m_nGetPos);39 }40 else41 {42 43 }44 return nLast;45 }46 47 static int AddToPipeBuf(void *pBuf,int nLen)48 {49 int nRes = -1;50 if(m_pPipeBuf != NULL)51 {52 int nPos = m_nNowPos % PIPE_LENTH;53 if ((nPos + nLen) > PIPE_LENTH)54 {55 int nCpLen = (PIPE_LENTH - nPos);56 memcpy(&m_pPipeBuf[nPos],pBuf,nCpLen);57 58 nPos = 0;59 memcpy(&m_pPipeBuf[0],&pBuf[nCpLen],nLen - nCpLen);60 }61 else62 {63 memcpy(&m_pPipeBuf[nPos],pBuf,nLen);64 }65 66 m_nNowPos = m_nNowPos + nLen;67 nRes = nLen;68 }69 70 return nRes;71 }72 73 static int GetSavedLen()74 {75 int nLen = 0;76 if (m_nNowPos == m_nGetPos)77 {78 nLen = 0;79 }80 else if(m_nNowPos > m_nGetPos)81 {82 nLen = m_nNowPos - m_nGetPos;83 }84 else85 {86 //異常,不存在87 }88 89 return nLen;90 }91 92 static int GetFromPipeBuf(void *pBuf,int nLen)93 {94 int nPos = (m_nGetPos % PIPE_LENTH);95 int nRes = -1;96 97 if (nLen > 0)98 {99 if ((nPos + nLen) > PIPE_LENTH) 100 { 101 int nCpLen = PIPE_LENTH - nPos; 102 //先拷貝末尾 103 memcpy(pBuf,&m_pPipeBuf[nPos],nCpLen); 104 nPos = 0; 105 memcpy(&pBuf[nCpLen], &m_pPipeBuf[0], nLen - nCpLen); 106 } 107 else 108 { 109 memcpy(pBuf,&m_pPipeBuf[nPos],nLen); 110 } 111 112 nRes = nLen; 113 m_nGetPos = m_nGetPos + nLen; 114 } 115 116 return nRes; 117 } 118 119 //添加數據(如果數據已滿,等待) 120 int Safe_AddBuf(char *pBuf,int nLen) 121 { 122 int nRes = -1; 123 if(((nLen + 4) > PIPE_LENTH) || (m_pPipeBuf == NULL)) 124 { 125 return nRes; 126 } 127 128 int bIsSaved = 0; 129 while (bIsSaved == 0) 130 { 131 pthread_mutex_lock(&m_lock); 132 int nLast = GetLastTemp(); 133 134 if(nLast >= (nLen + 4)) 135 { 136 char strNUM[5]; 137 memcpy(strNUM, &nLen, 4); 138 AddToPipeBuf(strNUM, 4); 139 140 nRes = AddToPipeBuf(pBuf, nLen); 141 bIsSaved = 1; 142 } 143 144 pthread_mutex_unlock(&m_lock); 145 146 if(bIsSaved == 0) 147 { 148 //< delay 10ms .continue waited 149 printf("Safe_SaveBuf: delay 10ms .continue waited\n"); 150 usleep(10000); 151 } 152 } 153 154 return nRes; 155 } 156 157 //提取數據(如果沒有數據,等待) 158 int Safe_GetBuf(char *pBuf,int nLen) 159 { 160 static int lastReadAll = 1; ///< 取完 161 static int nLastRead = 0; ///< 還有多少個沒讀完 162 163 int nRes = -1; 164 if((nLen <= 0) || (m_pPipeBuf == NULL)) 165 { 166 return 0; 167 } 168 169 int bIsGet = 0; 170 while (bIsGet == 0) 171 { 172 pthread_mutex_lock(&m_lock); 173 int nSaved = GetSavedLen(); 174 int nframe_length = 0; 175 176 if(nSaved > 0) 177 { 178 if(lastReadAll == 1) 179 { 180 if(nSaved > 4) 181 { 182 GetFromPipeBuf(&nframe_length,4); 183 184 if(nframe_length > nLen) 185 { 186 lastReadAll = 0; 187 188 nLastRead = nframe_length - nLen; 189 nframe_length = nLen; 190 //外部存儲 不夠(先不管,除非長度寫錯了) 191 } 192 else 193 { 194 //取走這幀 195 lastReadAll = 1; 196 nLastRead = 0; 197 } 198 } 199 else 200 { 201 //錯誤--- 202 } 203 } 204 else 205 { 206 //繼續- 207 if(nLen >= nLastRead) 208 { 209 //這次空間夠了 210 if(nSaved >= nLastRead) 211 { 212 //把上次未取走的 全部取走 213 nframe_length = nLastRead; 214 nLastRead = 0; 215 lastReadAll = 1; 216 } 217 else 218 { 219 nframe_length = nSaved; 220 nLastRead = nLastRead - nSaved; 221 lastReadAll = 0; 222 } 223 } 224 else 225 { 226 //空間不夠 nLastRead 227 if(nSaved >= nLen) 228 { 229 nframe_length = nLen; 230 nLastRead = nLastRead - nLen; 231 lastReadAll = 0; 232 } 233 else 234 { 235 nframe_length = nSaved; 236 nLastRead = nLastRead - nSaved; 237 lastReadAll = 0; 238 } 239 } 240 } 241 242 if(nframe_length > 0) 243 { 244 nRes = GetFromPipeBuf(pBuf, nframe_length); 245 bIsGet = 1; 246 } 247 } 248 249 pthread_mutex_unlock(&m_lock); 250 251 if(bIsGet == 0) 252 { 253 //< delay 100ms .continue waited 254 printf("Safe_GetBuf: delay 10ms .continue waited\n"); 255 usleep(10000); 256 } 257 } 258 return nRes; 259 } 260 261 int Safe_IsHaveData() 262 { 263 int nSaved = 0; 264 pthread_mutex_lock(&m_lock); 265 nSaved = GetSavedLen(); 266 pthread_mutex_unlock(&m_lock); 267 return nSaved; 268 }題外話,問題也解決了,效率非常高,cpu僅占3%~5%左右,性能上也很強勁,這款cpu不錯
很流暢,延時很少(100ms~200ms左右,感覺!)
總結
以上是生活随笔為你收集整理的关于IMX6Dl 芯片使用硬编解码的问题记录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Permute 3.6.5 小巧便捷的多
- 下一篇: Vim中数字自增、自减