关于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     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左右,感觉!)

猜你喜欢

转载自www.cnblogs.com/winafa/p/11962471.html