NXP出了IMX6系列芯片(如今應該是9系列最新了),性能至關於咱們嵌入式行業,已經很是優秀(能夠作不少事情)緩存
同時,IMX6DL IMX6Q 自帶vpu硬編解碼,用來處理下視頻也是很是不錯的,對於咱們來講的確很是合適異步
衆所周知,mxc_vpu_test.out 是官方提供的測試程序,用於測試各類功能,源碼也提供,函數
可是系統裏面源碼是跟其餘測試程序整合在一塊兒的,每每咱們想要在此基礎上改改弄弄,而後從新編譯是件困難的事情(大神除外)性能
固然,也能夠從網上下載 mxc_vpu_test.out 的源碼,貌似也有(csdn就有),但可能跟你板子的庫文件版本不一致,會致使各類問題測試
總之這是一個繞不過去的坑(編譯過不算,正常運行編解碼纔算)編碼
以上問題,困擾好久,後來版本搞對了,纔算順利過去。 ---- 記一下,若是用測試程序 編譯沒有問題,但測試解碼時候,出現段錯誤,每每是你所用h文件跟板子so庫用的h文件版本不同,也就是某些結構體size不同。spa
另一個問題:線程
假設在同一塊板子上,先採集USB攝像頭的數據,而後vpu編碼產生h264流,而後經過「管道」發送給解碼線程,解碼線程收到h264流,而後調用vpu的解碼,而後再顯示。固然這個步驟是異步的,兩個線程(進程),中間涉及到數據交互的。code
源代碼是參考 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 else 41 { 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 else 62 { 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 else 85 { 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左右,感受!)