]> git.vomp.tv Git - vompclient.git/blob - src/omx/omx.cc
Future bug fix.
[vompclient.git] / src / omx / omx.cc
1 /*
2     Copyright 2021 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include "../log.h"
21 #include "omximagedecode.h"
22 #include "omxeglrender.h"
23
24 #include "omx.h"
25
26 //static const char* TAG = "OMX";
27
28
29 // Static variable storage
30 OMX_Image_Decode* OMX::omx_image_decode{};
31 OMX_EGL_Render*   OMX::omx_egl_render{};
32
33 OMX_HANDLETYPE OMX::handle_image_decode{};
34 OMX_HANDLETYPE OMX::handle_egl_render{};
35
36 std::thread OMX::eventsProcessorThread;
37 std::mutex OMX::eventsProcessorMutex;
38 std::condition_variable OMX::eventsProcessorCond;
39 std::mutex OMX::eventsMutex;
40 Events OMX::events;
41 bool OMX::eventsProcessorWake{};
42 bool OMX::eventsProcessorShutdownNow{};
43 int OMX::eventsProcessorUsageCount{};
44 EventWaiters OMX::eventWaiters;
45 std::mutex OMX::eventWaitersMutex;
46
47
48 // Main static callbacks
49
50 OMX_ERRORTYPE OMX::scb_EventHandler(
51   OMX_IN OMX_HANDLETYPE handle, OMX_IN OMX_PTR appdata, OMX_IN OMX_EVENTTYPE event_type,
52   OMX_IN OMX_U32 data1, OMX_IN OMX_U32 data2, OMX_IN OMX_PTR event_data)
53 {
54 //   LogNT::getInstance()->debug("OMXSCB", "EventHandler {} {} {} {}", static_cast<void*>(handle_image_decode), static_cast<void*>(omx_image_decode), static_cast<void*>(handle_egl_render), static_cast<void*>(omx_egl_render));
55   if (handle == handle_image_decode)
56     return omx_image_decode->cb_EventHandler(handle, appdata, event_type, data1, data2, event_data);
57   else if (handle == handle_egl_render)
58     return omx_egl_render->cb_EventHandler(handle, appdata, event_type, data1, data2, event_data);
59
60   return OMX_ErrorNone;
61 }
62
63 OMX_ERRORTYPE OMX::scb_EmptyBufferDone(OMX_IN OMX_HANDLETYPE handle, OMX_IN OMX_PTR appdata, OMX_IN OMX_BUFFERHEADERTYPE* buffer)
64 {
65 //   LogNT::getInstance()->debug("OMXSCB", "EmptyBufferDone {} {} {} {}", static_cast<void*>(handle_image_decode), static_cast<void*>(omx_image_decode), static_cast<void*>(handle_egl_render), static_cast<void*>(omx_egl_render));
66   if (handle == handle_image_decode)
67     return omx_image_decode->cb_EmptyBufferDone(handle, appdata, buffer);
68   else if (handle == handle_egl_render)
69     return omx_egl_render->cb_EmptyBufferDone(handle, appdata, buffer);
70
71   return OMX_ErrorNone;
72 }
73
74 OMX_ERRORTYPE OMX::scb_FillBufferDone(OMX_IN OMX_HANDLETYPE handle, OMX_IN OMX_PTR appdata, OMX_IN OMX_BUFFERHEADERTYPE* buffer)
75 {
76 //   LogNT::getInstance()->debug("OMXSCB", "FillBufferDone {} {} {} {}", static_cast<void*>(handle_image_decode), static_cast<void*>(omx_image_decode), static_cast<void*>(handle_egl_render), static_cast<void*>(omx_egl_render));
77   if (handle == handle_image_decode)
78     return omx_image_decode->cb_FillBufferDone(handle, appdata, buffer);
79   else if (handle == handle_egl_render)
80     return omx_egl_render->cb_FillBufferDone(handle, appdata, buffer);
81   return OMX_ErrorNone;
82 }
83
84 // ---
85
86 OMX::OMX()
87 {
88   log = LogNT::getInstance();
89 }
90
91 OMX::~OMX()
92 {
93 }
94
95 // bool OMX::OMX_Master_Init()
96 // {
97 //   OMX_ERRORTYPE error;
98 //   error = OMX_Init();
99 //   if (error != OMX_ErrorNone) return false;
100 //   return true;
101 // }
102
103 OMX_ERRORTYPE OMX::cb_EventHandler(OMX_IN OMX_HANDLETYPE /* handle */, OMX_IN OMX_PTR appdata, OMX_IN OMX_EVENTTYPE event_type, OMX_IN OMX_U32 data1, OMX_IN OMX_U32 data2, OMX_IN OMX_PTR event_data)
104 {
105   //Log* l = Log::getInstance();
106 //   log->debug(TAG, "CB: eventHandler {} {} {:#x} {:#x} {}", static_cast<void*>(handle), event_type, data1, data2, static_cast<void*>(event_data));
107
108   eventsMutex.lock();
109   Event* incomingEvent = new Event{.appdata = appdata, .eventType = event_type, .data1 = data1, .data2 = data2, .event_data = event_data};
110   events.push_back(incomingEvent);
111   eventsMutex.unlock();
112
113   eventsProcessorMutex.lock();
114   eventsProcessorWake = true;
115   eventsProcessorMutex.unlock();
116   eventsProcessorCond.notify_one();
117
118 //   log->debug(TAG, "eventHandler end");
119   return OMX_ErrorNone;
120 }
121
122 void OMX::initEventsProcessing()
123 {
124   eventsProcessorMutex.lock();
125
126   if (eventsProcessorUsageCount == 0)
127   {
128     eventsProcessorUsageCount = 1;
129
130     eventsProcessorThread = std::thread( [&]
131     {
132       eventsProcessorMutex.lock();
133       eventsProcessorMutex.unlock();
134       eventsProcessorLoop();
135     });
136   }
137   else
138   {
139     ++eventsProcessorUsageCount;
140   }
141
142   eventsProcessorMutex.unlock();
143 }
144
145 void OMX::stopEventsProcessing()
146 {
147   eventsProcessorMutex.lock();
148
149   --eventsProcessorUsageCount;
150
151   if (eventsProcessorUsageCount == 0)
152   {
153     // stop event loop
154     eventsProcessorWake = true;
155     eventsProcessorShutdownNow = true;
156     eventsProcessorCond.notify_one();
157     eventsProcessorMutex.unlock();
158     eventsProcessorThread.join();
159     // eventsProcessorShutdownNow = false; // This is the fix.
160
161     // But where else triggers the bug?
162
163     abort();
164   }
165   else
166   {
167     eventsProcessorMutex.unlock();
168   }
169 }
170
171 void OMX::eventsProcessorLoop()
172 {
173   //LogNT* log = LogNT::getInstance();
174   std::unique_lock<std::mutex> ul(eventsProcessorMutex); // locks
175
176   while(1)
177   {
178     // locked
179     if (eventsProcessorWake)
180     {
181       eventsProcessorWake = false;
182       ul.unlock();
183
184       if (eventsProcessorShutdownNow) return;
185
186       eventsMutex.lock();
187       for (Events::iterator eventIterator = events.begin(); eventIterator != events.end(); )  // for each event received from OMX
188       {
189         Event* event = *eventIterator;
190
191         if (event->isNew)
192         {
193           event->isNew = false;
194
195           /*
196           log->debug(TAG, "Event Processor Loop - event:");
197
198           if (event->eventType == 0)
199             log->debug(TAG, "* eventType: OMX_EventCmdComplete");
200           else if (event->eventType == 1)
201             log->debug(TAG, "* eventType: OMX_EventError");
202           else if (event->eventType == 2)
203             log->debug(TAG, "* eventType: OMX_EventMark");
204           else if (event->eventType == 3)
205             log->debug(TAG, "* eventType: OMX_EventPortSettingsChanged");
206           else if (event->eventType == 4)
207             log->debug(TAG, "* eventType: OMX_EventBufferFlag");
208           else
209             log->debug(TAG, "* eventType: {:#x}", event->eventType);
210
211           if (event->eventType == OMX_EventCmdComplete)
212           {
213             if (event->data1 == OMX_CommandStateSet)
214               log->debug(TAG, "* OMX_COMMANDTYPE: OMX_CommandStateSet");
215             if (event->data1 == OMX_CommandFlush)
216               log->debug(TAG, "* OMX_COMMANDTYPE: OMX_CommandFlush");
217             if (event->data1 == OMX_CommandPortDisable)
218               log->debug(TAG, "* OMX_COMMANDTYPE: OMX_CommandPortDisable");
219             if (event->data1 == OMX_CommandPortEnable)
220               log->debug(TAG, "* OMX_COMMANDTYPE: OMX_CommandPortEnable");
221             if (event->data1 == OMX_CommandMarkBuffer)
222               log->debug(TAG, "* OMX_COMMANDTYPE: OMX_CommandMarkBuffer");
223
224             if (event->data1 == OMX_CommandStateSet)
225             {
226               log->debug(TAG, "* new state: {}", event->data2);
227             }
228
229             if ( (event->data1 == OMX_CommandPortEnable) ||  (event->data1 == OMX_CommandPortDisable) )
230             {
231               log->debug(TAG, "* port en/disabled: {}", event->data2);
232             }
233           }
234           else if (event->eventType == OMX_EventBufferFlag)
235           {
236             log->debug(TAG, "* Port: {:#x} {}", event->data1, event->data1);
237           }
238           else if (event->eventType == OMX_EventError)
239           {
240             log->debug(TAG, "* Error code: {:#x}", event->data1);
241
242             if (event->data1 == OMX_ErrorPortUnpopulated)
243               log->debug(TAG, "* = : OMX_ErrorPortUnpopulated");
244             if (event->data1 == OMX_ErrorInsufficientResources)
245               log->debug(TAG, "* =: OMX_ErrorInsufficientResources");
246           }
247           */
248
249         } // end if event is new (then print it out)
250
251
252         // Find matching EventWaiter
253
254         eventWaitersMutex.lock();
255
256         // Now have EventsMutex and eventWaitersMutex
257
258         EventWaiters::iterator eventWaiterIterator;
259         EventWaiter* eventWaiter{};
260
261         for (eventWaiterIterator = eventWaiters.begin(); eventWaiterIterator < eventWaiters.end(); eventWaiterIterator++)
262         {
263           // structure here not great yet
264           // not looking at eventWaiter->eventType??
265
266           eventWaiter = *eventWaiterIterator;
267
268           if (event->eventType == OMX_EventCmdComplete)
269           {
270             if (    ((event->data1 == OMX_CommandPortEnable) && (eventWaiter->command == OMX_CommandPortEnable))
271                 || ((event->data1 == OMX_CommandPortDisable) && (eventWaiter->command == OMX_CommandPortDisable))  )
272             {
273               if (event->data2 == eventWaiter->port)
274               {
275                 // Found!
276                 eventWaiter->receivedEvent = event;
277                 break;
278               }
279             }
280             else if ((event->data1 == OMX_CommandStateSet) && (eventWaiter->command == OMX_CommandStateSet))
281             {
282               if (event->data2 == eventWaiter->newState)
283               {
284                 // Found!
285                 eventWaiter->receivedEvent = event;
286                 break;
287               }
288             }
289             else if ((event->data1 == OMX_CommandFlush) && (eventWaiter->command == OMX_CommandFlush))
290             {
291               if (event->data2 == eventWaiter->flushPort)
292               {
293                 // Found!
294                 eventWaiter->receivedEvent = event;
295                 break;
296               }
297             }
298           }
299           else if (event->eventType == OMX_EventPortSettingsChanged)
300           {
301             if ( (eventWaiter->eventType == OMX_EventPortSettingsChanged)
302                 && (event->data1 == eventWaiter->port) )
303             {
304               // Found!
305               eventWaiter->receivedEvent = event;
306               break;
307             }
308           }
309         } // end of each eventWaiter loop
310
311
312         // Now obv we have an event, but do we have an eventWaiter? If not, advance and continue
313         if (!eventWaiter || (eventWaiterIterator == eventWaiters.end())) // A) none in the loop at all, B) none matched
314         {
315           eventWaitersMutex.unlock();
316
317           eventIterator++;
318           continue;
319         }
320
321         // Now we have an event (event, eventIterator) and a found eventWaiter (eventWaiter, eventWaiterIterator)
322
323         // Remove the eventWaiter from the deque
324         eventWaiters.erase(eventWaiterIterator);
325         eventWaitersMutex.unlock();
326
327         // Remove the event from the deque
328         eventIterator = events.erase(eventIterator);
329
330         // Iterators are now dead.
331         // Now we have an event and an eventWaiter
332         // Still have the EventsMutex but we have released the eventWaitersMutex.
333
334 //         log->debug(TAG, "This event {} found an event waiter for it {}", static_cast<void*>(event), static_cast<void*>(eventWaiter));
335
336
337         if (eventWaiter->waiting)
338         {
339           // FIXME look at whether eventWaiter could miss this signal
340 //           log->debug(TAG, "Notifying eventWaiter: {} on cond {}", static_cast<void*>(eventWaiter), static_cast<void*>(&eventWaiter->cond));
341           eventWaiter->cond.notify_one();
342         }
343         else
344         {
345 //           log->debug(TAG, "EventWaiter not waiting. Deleting {}", static_cast<void*>(eventWaiter));
346           delete event;
347           delete eventWaiter;
348         }
349
350 //         log->debug(TAG, "Done processing eventWaiter, goaround events loop");
351
352
353       } // end for each received event
354
355       // FIXME If there are events still in events that have not been matched up and sent
356       // to an eventWaiter, or that were not marked as waiting so we deleted it here, then this is a bug
357       eventsMutex.unlock();
358
359       // Reacquire eventsProcessor lock
360       ul.lock();
361     } // end if event processor wake
362
363     // locked
364
365     eventsProcessorCond.wait(ul, [&] { return eventsProcessorWake; });
366
367     // relocked, loop
368   } // while(1)
369 }
370
371 void OMX::enablePort(OMX_U32 port, bool enable, bool wait)
372 {
373   OMX_ERRORTYPE error;
374
375   OMX_PARAM_PORTDEFINITIONTYPE pdt;
376   memset(&pdt, 0, sizeof(pdt));
377   pdt.nSize = sizeof(pdt);
378   pdt.nVersion.nVersion = OMX_VERSION;
379   pdt.nPortIndex = port;
380   #pragma GCC diagnostic push
381   #pragma GCC diagnostic ignored "-Wold-style-cast"
382   error = OMX_GetParameter(componentHandle, OMX_IndexParamPortDefinition, &pdt);
383   #pragma GCC diagnostic pop
384   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_GetParameter in OMX::enablePort()", error);
385
386   if (pdt.bEnabled == enable) return; // already in requested state
387
388   std::unique_lock<std::mutex> ul(eventWaitersMutex);
389
390   OMX_COMMANDTYPE command = enable ? OMX_CommandPortEnable : OMX_CommandPortDisable;
391
392 //   log->debug(TAG, "en/disablePort: port: {:#x}, command: {:#x}", port, command);
393   #pragma GCC diagnostic push
394   #pragma GCC diagnostic ignored "-Wold-style-cast"
395   error = OMX_SendCommand(componentHandle, command, port, 0);
396   #pragma GCC diagnostic pop
397   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_SendCommand in OMX::enablePort()", error);
398 //   log->debug(TAG, "en/disablePort: port: {:#x}, command: {:#x} done", port, command);
399
400   EventWaiter* eventWaiter = new EventWaiter();
401   eventWaiter->waiting = wait;
402   eventWaiter->command = command;
403   eventWaiter->port = port;
404
405   eventWaiters.push_back(eventWaiter);
406
407   if (!wait) return; // && unlock. eventWaiter becomes owned by eventProcessor thread
408
409 //   log->debug(TAG, "en/disablePort: Going to wait on cond {}", static_cast<void*>(&eventWaiter->cond));
410   eventWaiter->cond.wait(ul);  // sleep this thread
411 //   log->debug(TAG, "en/disablePort: Back from wait on cond {}", static_cast<void*>(&eventWaiter->cond));
412   ul.unlock();
413
414
415   if (eventWaiter->receivedEvent)
416   {
417     // The event processor thread received an event and saved it here
418 //     log->debug(TAG, "received event!");
419     delete eventWaiter->receivedEvent;
420     delete eventWaiter;
421   }
422   else
423   {
424     delete eventWaiter; // This is ours, at least we can clean this up
425     throw OMX_Exception("Failed to receive event!", 0);
426   }
427 }
428
429 void OMX::changeState(OMX_STATETYPE reqState, bool wait)
430 {
431   OMX_STATETYPE currentState;
432   #pragma GCC diagnostic push
433   #pragma GCC diagnostic ignored "-Wold-style-cast"
434   OMX_GetState(componentHandle, &currentState);
435   #pragma GCC diagnostic pop
436 //   log->debug(TAG, "Current state: {}", currentState);
437   if (currentState == reqState)
438   {
439 //     log->debug(TAG, "changeState return immediately, already in reqState");
440     return;
441   }
442
443   std::unique_lock<std::mutex> ul(eventWaitersMutex);
444   #pragma GCC diagnostic push
445   #pragma GCC diagnostic ignored "-Wold-style-cast"
446   OMX_ERRORTYPE error = OMX_SendCommand(componentHandle, OMX_CommandStateSet, reqState, 0);
447   #pragma GCC diagnostic pop
448   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_SendCommand in OMX::changeState()", error);
449
450   EventWaiter* eventWaiter = new EventWaiter();
451   eventWaiter->waiting = wait;
452   eventWaiter->command = OMX_CommandStateSet;
453   eventWaiter->newState = reqState;
454
455   eventWaiters.push_back(eventWaiter);
456
457   if (!wait) return; // && unlock. eventWaiter becomes owned by eventProcessor thread
458
459 //   log->debug(TAG, "changeState: Going to wait on cond {}", static_cast<void*>(&eventWaiter->cond));
460   eventWaiter->cond.wait(ul);  // sleep this thread
461 //   log->debug(TAG, "changeState: Back from wait on cond {}", static_cast<void*>(&eventWaiter->cond));
462   ul.unlock();
463
464   if (eventWaiter->receivedEvent)
465   {
466     // The event processor thread received an event and saved it here
467 //     log->debug(TAG, "received event!");
468     delete eventWaiter->receivedEvent;
469     delete eventWaiter;
470   }
471   else
472   {
473     delete eventWaiter; // This is ours, at least we can clean this up
474     throw OMX_Exception("Failed to receive event!", 0);
475   }
476 }
477
478 void OMX::flushCommands(OMX_U32 port, bool wait)
479 {
480   std::unique_lock<std::mutex> ul(eventWaitersMutex);
481
482   #pragma GCC diagnostic push
483   #pragma GCC diagnostic ignored "-Wold-style-cast"
484   OMX_ERRORTYPE error = OMX_SendCommand(componentHandle, OMX_CommandFlush, port, NULL);
485   #pragma GCC diagnostic pop
486   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_SendCommand in OMX::flushCommands()", error);
487
488   EventWaiter* eventWaiter = new EventWaiter();
489   eventWaiter->waiting = wait;
490   eventWaiter->command = OMX_CommandFlush;
491   eventWaiter->flushPort = port;
492
493   eventWaiters.push_back(eventWaiter);
494
495   if (!wait) return; // && unlock. eventWaiter becomes owned by eventProcessor thread
496
497 //   log->debug(TAG, "flushCommands: Going to wait on cond {}", static_cast<void*>(&eventWaiter->cond));
498   eventWaiter->cond.wait(ul);  // sleep this thread
499 //   log->debug(TAG, "flushCommands: Back from wait on cond {}", static_cast<void*>(&eventWaiter->cond));
500   ul.unlock();
501
502   if (!eventWaiter->receivedEvent)
503   {
504     delete eventWaiter;
505     throw OMX_Exception("Error waiting for event in flushCommands", 0);
506   }
507
508   // The event processor thread received an event and saved it here
509 //   log->debug(TAG, "received event!");
510   delete eventWaiter->receivedEvent;
511   delete eventWaiter;
512 }