2 Copyright 2021 Chris Tallon
4 This file is part of VOMP.
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.
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.
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/>.
21 #include "omximagedecode.h"
22 #include "omxeglrender.h"
26 //static const char* TAG = "OMX";
29 // Static variable storage
30 OMX_Image_Decode* OMX::omx_image_decode{};
31 OMX_EGL_Render* OMX::omx_egl_render{};
33 OMX_HANDLETYPE OMX::handle_image_decode{};
34 OMX_HANDLETYPE OMX::handle_egl_render{};
36 std::thread OMX::eventsProcessorThread;
37 std::mutex OMX::eventsProcessorMutex;
38 std::condition_variable OMX::eventsProcessorCond;
39 std::mutex OMX::eventsMutex;
41 bool OMX::eventsProcessorWake{};
42 bool OMX::eventsProcessorShutdownNow{};
43 int OMX::eventsProcessorUsageCount{};
44 EventWaiters OMX::eventWaiters;
45 std::mutex OMX::eventWaitersMutex;
48 // Main static callbacks
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)
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);
63 OMX_ERRORTYPE OMX::scb_EmptyBufferDone(OMX_IN OMX_HANDLETYPE handle, OMX_IN OMX_PTR appdata, OMX_IN OMX_BUFFERHEADERTYPE* buffer)
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);
74 OMX_ERRORTYPE OMX::scb_FillBufferDone(OMX_IN OMX_HANDLETYPE handle, OMX_IN OMX_PTR appdata, OMX_IN OMX_BUFFERHEADERTYPE* buffer)
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);
88 log = LogNT::getInstance();
95 // bool OMX::OMX_Master_Init()
97 // OMX_ERRORTYPE error;
98 // error = OMX_Init();
99 // if (error != OMX_ErrorNone) return false;
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)
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));
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();
113 eventsProcessorMutex.lock();
114 eventsProcessorWake = true;
115 eventsProcessorMutex.unlock();
116 eventsProcessorCond.notify_one();
118 // log->debug(TAG, "eventHandler end");
119 return OMX_ErrorNone;
122 void OMX::initEventsProcessing()
124 eventsProcessorMutex.lock();
126 if (eventsProcessorUsageCount == 0)
128 eventsProcessorUsageCount = 1;
130 eventsProcessorThread = std::thread( [&]
132 eventsProcessorMutex.lock();
133 eventsProcessorMutex.unlock();
134 eventsProcessorLoop();
139 ++eventsProcessorUsageCount;
142 eventsProcessorMutex.unlock();
145 void OMX::stopEventsProcessing()
147 eventsProcessorMutex.lock();
149 --eventsProcessorUsageCount;
151 if (eventsProcessorUsageCount == 0)
154 eventsProcessorWake = true;
155 eventsProcessorShutdownNow = true;
156 eventsProcessorCond.notify_one();
157 eventsProcessorMutex.unlock();
158 eventsProcessorThread.join();
162 eventsProcessorMutex.unlock();
166 void OMX::eventsProcessorLoop()
168 //LogNT* log = LogNT::getInstance();
169 std::unique_lock<std::mutex> ul(eventsProcessorMutex); // locks
174 if (eventsProcessorWake)
176 eventsProcessorWake = false;
179 if (eventsProcessorShutdownNow) return;
182 for (Events::iterator eventIterator = events.begin(); eventIterator != events.end(); ) // for each event received from OMX
184 Event* event = *eventIterator;
188 event->isNew = false;
191 log->debug(TAG, "Event Processor Loop - event:");
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");
204 log->debug(TAG, "* eventType: {:#x}", event->eventType);
206 if (event->eventType == OMX_EventCmdComplete)
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");
219 if (event->data1 == OMX_CommandStateSet)
221 log->debug(TAG, "* new state: {}", event->data2);
224 if ( (event->data1 == OMX_CommandPortEnable) || (event->data1 == OMX_CommandPortDisable) )
226 log->debug(TAG, "* port en/disabled: {}", event->data2);
229 else if (event->eventType == OMX_EventBufferFlag)
231 log->debug(TAG, "* Port: {:#x} {}", event->data1, event->data1);
233 else if (event->eventType == OMX_EventError)
235 log->debug(TAG, "* Error code: {:#x}", event->data1);
237 if (event->data1 == OMX_ErrorPortUnpopulated)
238 log->debug(TAG, "* = : OMX_ErrorPortUnpopulated");
239 if (event->data1 == OMX_ErrorInsufficientResources)
240 log->debug(TAG, "* =: OMX_ErrorInsufficientResources");
244 } // end if event is new (then print it out)
247 // Find matching EventWaiter
249 eventWaitersMutex.lock();
251 // Now have EventsMutex and eventWaitersMutex
253 EventWaiters::iterator eventWaiterIterator;
254 EventWaiter* eventWaiter{};
256 for (eventWaiterIterator = eventWaiters.begin(); eventWaiterIterator < eventWaiters.end(); eventWaiterIterator++)
258 // structure here not great yet
259 // not looking at eventWaiter->eventType??
261 eventWaiter = *eventWaiterIterator;
263 if (event->eventType == OMX_EventCmdComplete)
265 if ( ((event->data1 == OMX_CommandPortEnable) && (eventWaiter->command == OMX_CommandPortEnable))
266 || ((event->data1 == OMX_CommandPortDisable) && (eventWaiter->command == OMX_CommandPortDisable)) )
268 if (event->data2 == eventWaiter->port)
271 eventWaiter->receivedEvent = event;
275 else if ((event->data1 == OMX_CommandStateSet) && (eventWaiter->command == OMX_CommandStateSet))
277 if (event->data2 == eventWaiter->newState)
280 eventWaiter->receivedEvent = event;
284 else if ((event->data1 == OMX_CommandFlush) && (eventWaiter->command == OMX_CommandFlush))
286 if (event->data2 == eventWaiter->flushPort)
289 eventWaiter->receivedEvent = event;
294 else if (event->eventType == OMX_EventPortSettingsChanged)
296 if ( (eventWaiter->eventType == OMX_EventPortSettingsChanged)
297 && (event->data1 == eventWaiter->port) )
300 eventWaiter->receivedEvent = event;
304 } // end of each eventWaiter loop
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
310 eventWaitersMutex.unlock();
316 // Now we have an event (event, eventIterator) and a found eventWaiter (eventWaiter, eventWaiterIterator)
318 // Remove the eventWaiter from the deque
319 eventWaiters.erase(eventWaiterIterator);
320 eventWaitersMutex.unlock();
322 // Remove the event from the deque
323 eventIterator = events.erase(eventIterator);
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.
329 // log->debug(TAG, "This event {} found an event waiter for it {}", static_cast<void*>(event), static_cast<void*>(eventWaiter));
332 if (eventWaiter->waiting)
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();
340 // log->debug(TAG, "EventWaiter not waiting. Deleting {}", static_cast<void*>(eventWaiter));
345 // log->debug(TAG, "Done processing eventWaiter, goaround events loop");
348 } // end for each received event
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();
354 // Reacquire eventsProcessor lock
356 } // end if event processor wake
360 eventsProcessorCond.wait(ul, [&] { return eventsProcessorWake; });
366 void OMX::enablePort(OMX_U32 port, bool enable, bool wait)
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);
381 if (pdt.bEnabled == enable) return; // already in requested state
383 std::unique_lock<std::mutex> ul(eventWaitersMutex);
385 OMX_COMMANDTYPE command = enable ? OMX_CommandPortEnable : OMX_CommandPortDisable;
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);
395 EventWaiter* eventWaiter = new EventWaiter();
396 eventWaiter->waiting = wait;
397 eventWaiter->command = command;
398 eventWaiter->port = port;
400 eventWaiters.push_back(eventWaiter);
402 if (!wait) return; // && unlock. eventWaiter becomes owned by eventProcessor thread
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));
410 if (eventWaiter->receivedEvent)
412 // The event processor thread received an event and saved it here
413 // log->debug(TAG, "received event!");
414 delete eventWaiter->receivedEvent;
419 delete eventWaiter; // This is ours, at least we can clean this up
420 throw OMX_Exception("Failed to receive event!", 0);
424 void OMX::changeState(OMX_STATETYPE reqState, bool wait)
426 OMX_STATETYPE currentState;
427 #pragma GCC diagnostic push
428 #pragma GCC diagnostic ignored "-Wold-style-cast"
429 OMX_GetState(componentHandle, ¤tState);
430 #pragma GCC diagnostic pop
431 // log->debug(TAG, "Current state: {}", currentState);
432 if (currentState == reqState)
434 // log->debug(TAG, "changeState return immediately, already in reqState");
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);
445 EventWaiter* eventWaiter = new EventWaiter();
446 eventWaiter->waiting = wait;
447 eventWaiter->command = OMX_CommandStateSet;
448 eventWaiter->newState = reqState;
450 eventWaiters.push_back(eventWaiter);
452 if (!wait) return; // && unlock. eventWaiter becomes owned by eventProcessor thread
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));
459 if (eventWaiter->receivedEvent)
461 // The event processor thread received an event and saved it here
462 // log->debug(TAG, "received event!");
463 delete eventWaiter->receivedEvent;
468 delete eventWaiter; // This is ours, at least we can clean this up
469 throw OMX_Exception("Failed to receive event!", 0);
473 void OMX::flushCommands(OMX_U32 port, bool wait)
475 std::unique_lock<std::mutex> ul(eventWaitersMutex);
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);
483 EventWaiter* eventWaiter = new EventWaiter();
484 eventWaiter->waiting = wait;
485 eventWaiter->command = OMX_CommandFlush;
486 eventWaiter->flushPort = port;
488 eventWaiters.push_back(eventWaiter);
490 if (!wait) return; // && unlock. eventWaiter becomes owned by eventProcessor thread
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));
497 if (!eventWaiter->receivedEvent)
500 throw OMX_Exception("Error waiting for event in flushCommands", 0);
503 // The event processor thread received an event and saved it here
504 // log->debug(TAG, "received event!");
505 delete eventWaiter->receivedEvent;