]> git.vomp.tv Git - vompclient.git/blob - src/omx/omx.cc
Switch to cmake
[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   }
160   else
161   {
162     eventsProcessorMutex.unlock();
163   }
164 }
165
166 void OMX::eventsProcessorLoop()
167 {
168   //LogNT* log = LogNT::getInstance();
169   std::unique_lock<std::mutex> ul(eventsProcessorMutex); // locks
170
171   while(1)
172   {
173     // locked
174     if (eventsProcessorWake)
175     {
176       eventsProcessorWake = false;
177       ul.unlock();
178
179       if (eventsProcessorShutdownNow) return;
180
181       eventsMutex.lock();
182       for (Events::iterator eventIterator = events.begin(); eventIterator != events.end(); )  // for each event received from OMX
183       {
184         Event* event = *eventIterator;
185
186         if (event->isNew)
187         {
188           event->isNew = false;
189
190           /*
191           log->debug(TAG, "Event Processor Loop - event:");
192
193           if (event->eventType == 0)
194             log->debug(TAG, "* eventType: OMX_EventCmdComplete");
195           else if (event->eventType == 1)
196             log->debug(TAG, "* eventType: OMX_EventError");
197           else if (event->eventType == 2)
198             log->debug(TAG, "* eventType: OMX_EventMark");
199           else if (event->eventType == 3)
200             log->debug(TAG, "* eventType: OMX_EventPortSettingsChanged");
201           else if (event->eventType == 4)
202             log->debug(TAG, "* eventType: OMX_EventBufferFlag");
203           else
204             log->debug(TAG, "* eventType: {:#x}", event->eventType);
205
206           if (event->eventType == OMX_EventCmdComplete)
207           {
208             if (event->data1 == OMX_CommandStateSet)
209               log->debug(TAG, "* OMX_COMMANDTYPE: OMX_CommandStateSet");
210             if (event->data1 == OMX_CommandFlush)
211               log->debug(TAG, "* OMX_COMMANDTYPE: OMX_CommandFlush");
212             if (event->data1 == OMX_CommandPortDisable)
213               log->debug(TAG, "* OMX_COMMANDTYPE: OMX_CommandPortDisable");
214             if (event->data1 == OMX_CommandPortEnable)
215               log->debug(TAG, "* OMX_COMMANDTYPE: OMX_CommandPortEnable");
216             if (event->data1 == OMX_CommandMarkBuffer)
217               log->debug(TAG, "* OMX_COMMANDTYPE: OMX_CommandMarkBuffer");
218
219             if (event->data1 == OMX_CommandStateSet)
220             {
221               log->debug(TAG, "* new state: {}", event->data2);
222             }
223
224             if ( (event->data1 == OMX_CommandPortEnable) ||  (event->data1 == OMX_CommandPortDisable) )
225             {
226               log->debug(TAG, "* port en/disabled: {}", event->data2);
227             }
228           }
229           else if (event->eventType == OMX_EventBufferFlag)
230           {
231             log->debug(TAG, "* Port: {:#x} {}", event->data1, event->data1);
232           }
233           else if (event->eventType == OMX_EventError)
234           {
235             log->debug(TAG, "* Error code: {:#x}", event->data1);
236
237             if (event->data1 == OMX_ErrorPortUnpopulated)
238               log->debug(TAG, "* = : OMX_ErrorPortUnpopulated");
239             if (event->data1 == OMX_ErrorInsufficientResources)
240               log->debug(TAG, "* =: OMX_ErrorInsufficientResources");
241           }
242           */
243
244         } // end if event is new (then print it out)
245
246
247         // Find matching EventWaiter
248
249         eventWaitersMutex.lock();
250
251         // Now have EventsMutex and eventWaitersMutex
252
253         EventWaiters::iterator eventWaiterIterator;
254         EventWaiter* eventWaiter{};
255
256         for (eventWaiterIterator = eventWaiters.begin(); eventWaiterIterator < eventWaiters.end(); eventWaiterIterator++)
257         {
258           // structure here not great yet
259           // not looking at eventWaiter->eventType??
260
261           eventWaiter = *eventWaiterIterator;
262
263           if (event->eventType == OMX_EventCmdComplete)
264           {
265             if (    ((event->data1 == OMX_CommandPortEnable) && (eventWaiter->command == OMX_CommandPortEnable))
266                 || ((event->data1 == OMX_CommandPortDisable) && (eventWaiter->command == OMX_CommandPortDisable))  )
267             {
268               if (event->data2 == eventWaiter->port)
269               {
270                 // Found!
271                 eventWaiter->receivedEvent = event;
272                 break;
273               }
274             }
275             else if ((event->data1 == OMX_CommandStateSet) && (eventWaiter->command == OMX_CommandStateSet))
276             {
277               if (event->data2 == eventWaiter->newState)
278               {
279                 // Found!
280                 eventWaiter->receivedEvent = event;
281                 break;
282               }
283             }
284             else if ((event->data1 == OMX_CommandFlush) && (eventWaiter->command == OMX_CommandFlush))
285             {
286               if (event->data2 == eventWaiter->flushPort)
287               {
288                 // Found!
289                 eventWaiter->receivedEvent = event;
290                 break;
291               }
292             }
293           }
294           else if (event->eventType == OMX_EventPortSettingsChanged)
295           {
296             if ( (eventWaiter->eventType == OMX_EventPortSettingsChanged)
297                 && (event->data1 == eventWaiter->port) )
298             {
299               // Found!
300               eventWaiter->receivedEvent = event;
301               break;
302             }
303           }
304         } // end of each eventWaiter loop
305
306
307         // Now obv we have an event, but do we have an eventWaiter? If not, advance and continue
308         if (!eventWaiter || (eventWaiterIterator == eventWaiters.end())) // A) none in the loop at all, B) none matched
309         {
310           eventWaitersMutex.unlock();
311
312           eventIterator++;
313           continue;
314         }
315
316         // Now we have an event (event, eventIterator) and a found eventWaiter (eventWaiter, eventWaiterIterator)
317
318         // Remove the eventWaiter from the deque
319         eventWaiters.erase(eventWaiterIterator);
320         eventWaitersMutex.unlock();
321
322         // Remove the event from the deque
323         eventIterator = events.erase(eventIterator);
324
325         // Iterators are now dead.
326         // Now we have an event and an eventWaiter
327         // Still have the EventsMutex but we have released the eventWaitersMutex.
328
329 //         log->debug(TAG, "This event {} found an event waiter for it {}", static_cast<void*>(event), static_cast<void*>(eventWaiter));
330
331
332         if (eventWaiter->waiting)
333         {
334           // FIXME look at whether eventWaiter could miss this signal
335 //           log->debug(TAG, "Notifying eventWaiter: {} on cond {}", static_cast<void*>(eventWaiter), static_cast<void*>(&eventWaiter->cond));
336           eventWaiter->cond.notify_one();
337         }
338         else
339         {
340 //           log->debug(TAG, "EventWaiter not waiting. Deleting {}", static_cast<void*>(eventWaiter));
341           delete event;
342           delete eventWaiter;
343         }
344
345 //         log->debug(TAG, "Done processing eventWaiter, goaround events loop");
346
347
348       } // end for each received event
349
350       // FIXME If there are events still in events that have not been matched up and sent
351       // to an eventWaiter, or that were not marked as waiting so we deleted it here, then this is a bug
352       eventsMutex.unlock();
353
354       // Reacquire eventsProcessor lock
355       ul.lock();
356     } // end if event processor wake
357
358     // locked
359
360     eventsProcessorCond.wait(ul, [&] { return eventsProcessorWake; });
361
362     // relocked, loop
363   } // while(1)
364 }
365
366 void OMX::enablePort(OMX_U32 port, bool enable, bool wait)
367 {
368   OMX_ERRORTYPE error;
369
370   OMX_PARAM_PORTDEFINITIONTYPE pdt;
371   memset(&pdt, 0, sizeof(pdt));
372   pdt.nSize = sizeof(pdt);
373   pdt.nVersion.nVersion = OMX_VERSION;
374   pdt.nPortIndex = port;
375   #pragma GCC diagnostic push
376   #pragma GCC diagnostic ignored "-Wold-style-cast"
377   error = OMX_GetParameter(componentHandle, OMX_IndexParamPortDefinition, &pdt);
378   #pragma GCC diagnostic pop
379   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_GetParameter in OMX::enablePort()", error);
380
381   if (pdt.bEnabled == enable) return; // already in requested state
382
383   std::unique_lock<std::mutex> ul(eventWaitersMutex);
384
385   OMX_COMMANDTYPE command = enable ? OMX_CommandPortEnable : OMX_CommandPortDisable;
386
387 //   log->debug(TAG, "en/disablePort: port: {:#x}, command: {:#x}", port, command);
388   #pragma GCC diagnostic push
389   #pragma GCC diagnostic ignored "-Wold-style-cast"
390   error = OMX_SendCommand(componentHandle, command, port, 0);
391   #pragma GCC diagnostic pop
392   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_SendCommand in OMX::enablePort()", error);
393 //   log->debug(TAG, "en/disablePort: port: {:#x}, command: {:#x} done", port, command);
394
395   EventWaiter* eventWaiter = new EventWaiter();
396   eventWaiter->waiting = wait;
397   eventWaiter->command = command;
398   eventWaiter->port = port;
399
400   eventWaiters.push_back(eventWaiter);
401
402   if (!wait) return; // && unlock. eventWaiter becomes owned by eventProcessor thread
403
404 //   log->debug(TAG, "en/disablePort: Going to wait on cond {}", static_cast<void*>(&eventWaiter->cond));
405   eventWaiter->cond.wait(ul);  // sleep this thread
406 //   log->debug(TAG, "en/disablePort: Back from wait on cond {}", static_cast<void*>(&eventWaiter->cond));
407   ul.unlock();
408
409
410   if (eventWaiter->receivedEvent)
411   {
412     // The event processor thread received an event and saved it here
413 //     log->debug(TAG, "received event!");
414     delete eventWaiter->receivedEvent;
415     delete eventWaiter;
416   }
417   else
418   {
419     delete eventWaiter; // This is ours, at least we can clean this up
420     throw OMX_Exception("Failed to receive event!", 0);
421   }
422 }
423
424 void OMX::changeState(OMX_STATETYPE reqState, bool wait)
425 {
426   OMX_STATETYPE currentState;
427   #pragma GCC diagnostic push
428   #pragma GCC diagnostic ignored "-Wold-style-cast"
429   OMX_GetState(componentHandle, &currentState);
430   #pragma GCC diagnostic pop
431 //   log->debug(TAG, "Current state: {}", currentState);
432   if (currentState == reqState)
433   {
434 //     log->debug(TAG, "changeState return immediately, already in reqState");
435     return;
436   }
437
438   std::unique_lock<std::mutex> ul(eventWaitersMutex);
439   #pragma GCC diagnostic push
440   #pragma GCC diagnostic ignored "-Wold-style-cast"
441   OMX_ERRORTYPE error = OMX_SendCommand(componentHandle, OMX_CommandStateSet, reqState, 0);
442   #pragma GCC diagnostic pop
443   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_SendCommand in OMX::changeState()", error);
444
445   EventWaiter* eventWaiter = new EventWaiter();
446   eventWaiter->waiting = wait;
447   eventWaiter->command = OMX_CommandStateSet;
448   eventWaiter->newState = reqState;
449
450   eventWaiters.push_back(eventWaiter);
451
452   if (!wait) return; // && unlock. eventWaiter becomes owned by eventProcessor thread
453
454 //   log->debug(TAG, "changeState: Going to wait on cond {}", static_cast<void*>(&eventWaiter->cond));
455   eventWaiter->cond.wait(ul);  // sleep this thread
456 //   log->debug(TAG, "changeState: Back from wait on cond {}", static_cast<void*>(&eventWaiter->cond));
457   ul.unlock();
458
459   if (eventWaiter->receivedEvent)
460   {
461     // The event processor thread received an event and saved it here
462 //     log->debug(TAG, "received event!");
463     delete eventWaiter->receivedEvent;
464     delete eventWaiter;
465   }
466   else
467   {
468     delete eventWaiter; // This is ours, at least we can clean this up
469     throw OMX_Exception("Failed to receive event!", 0);
470   }
471 }
472
473 void OMX::flushCommands(OMX_U32 port, bool wait)
474 {
475   std::unique_lock<std::mutex> ul(eventWaitersMutex);
476
477   #pragma GCC diagnostic push
478   #pragma GCC diagnostic ignored "-Wold-style-cast"
479   OMX_ERRORTYPE error = OMX_SendCommand(componentHandle, OMX_CommandFlush, port, NULL);
480   #pragma GCC diagnostic pop
481   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_SendCommand in OMX::flushCommands()", error);
482
483   EventWaiter* eventWaiter = new EventWaiter();
484   eventWaiter->waiting = wait;
485   eventWaiter->command = OMX_CommandFlush;
486   eventWaiter->flushPort = port;
487
488   eventWaiters.push_back(eventWaiter);
489
490   if (!wait) return; // && unlock. eventWaiter becomes owned by eventProcessor thread
491
492 //   log->debug(TAG, "flushCommands: Going to wait on cond {}", static_cast<void*>(&eventWaiter->cond));
493   eventWaiter->cond.wait(ul);  // sleep this thread
494 //   log->debug(TAG, "flushCommands: Back from wait on cond {}", static_cast<void*>(&eventWaiter->cond));
495   ul.unlock();
496
497   if (!eventWaiter->receivedEvent)
498   {
499     delete eventWaiter;
500     throw OMX_Exception("Error waiting for event in flushCommands", 0);
501   }
502
503   // The event processor thread received an event and saved it here
504 //   log->debug(TAG, "received event!");
505   delete eventWaiter->receivedEvent;
506   delete eventWaiter;
507 }