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/>.
20 #include <VG/openvg.h>
22 #include <EGL/eglext.h>
26 #include "omxeglrender.h"
28 static const char* TAG = "OMX_EGL_Render";
31 OMX_EGL_Render::OMX_EGL_Render()
33 omx_egl_render = this;
36 OMX_EGL_Render::~OMX_EGL_Render()
38 omx_image_decode = NULL;
39 handle_egl_render = 0;
42 bool OMX_EGL_Render::init()
44 initEventsProcessing();
46 OMX_CALLBACKTYPE callbacks = {&scb_EventHandler, &scb_EmptyBufferDone, &scb_FillBufferDone};
49 asprintf(&componentName, "%s", componentName_egl_render);
50 OMX_ERRORTYPE error = OMX_GetHandle(&componentHandle, componentName, NULL, &callbacks);
52 // log->debug(TAG, "HANDLE ALLOC: OMX_EGL_Render: {} error: {:#x}", static_cast<void*>(componentHandle), error);
53 if (error != OMX_ErrorNone) return false;
55 handle_egl_render = componentHandle;
57 OMX_PORT_PARAM_TYPE p_param;
58 memset(&p_param, 0, sizeof(p_param));
59 p_param.nSize = sizeof(p_param);
60 p_param.nVersion.nVersion = OMX_VERSION;
62 #pragma GCC diagnostic push
63 #pragma GCC diagnostic ignored "-Wold-style-cast"
64 error = OMX_GetParameter(componentHandle, OMX_IndexParamVideoInit, &p_param);
65 #pragma GCC diagnostic pop
66 if (error != OMX_ErrorNone) return false;
68 inputPort = p_param.nStartPortNumber;
69 outputPort = p_param.nStartPortNumber + 1;
71 // log->debug(TAG, "IN: {}, OUT: {}", inputPort, outputPort);
75 void OMX_EGL_Render::shutdown()
77 stopEventsProcessing();
78 OMX_ERRORTYPE error = OMX_FreeHandle(componentHandle);
79 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_FreeHandle in OMX_EGL_Render::shutdown()", error);
82 void OMX_EGL_Render::prepareInputPort(OMX_U32 frameWidth, OMX_U32 frameHeight, OMX_U32 stride)
84 // log->debug(TAG, "prepareInputPort");
86 // Calculate a slice height. It must be divisible by 16 and >= frameHeight
87 // Temporarily use sliceHeight for remainder
88 int sliceHeight = frameHeight % 16;
90 sliceHeight = frameHeight;
92 sliceHeight = frameHeight + 16 - sliceHeight;
94 // Buffer size IS THE SLICE HEIGHT multiplied by the stride
95 inputPortBufferSize = sliceHeight * stride;
98 OMX_PARAM_PORTDEFINITIONTYPE portConfig;
99 memset(&portConfig, 0, sizeof(portConfig));
100 portConfig.nSize = sizeof(portConfig);
101 portConfig.nVersion.nVersion = OMX_VERSION;
102 portConfig.nPortIndex = inputPort;
104 #pragma GCC diagnostic push
105 #pragma GCC diagnostic ignored "-Wold-style-cast"
106 OMX_ERRORTYPE error = OMX_GetParameter(componentHandle, OMX_IndexParamPortDefinition, &portConfig);
107 #pragma GCC diagnostic pop
108 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_GetParameter in OMX_EGL_Render::prepareInputPort()", error);
111 log->debug(TAG, "Recv from get:");
112 log->debug(TAG, "nPortIndex: {}", portConfig.nPortIndex);
113 log->debug(TAG, "eDir: {}", portConfig.eDir);
114 log->debug(TAG, "buffer count actual: {}", portConfig.nBufferCountActual);
115 log->debug(TAG, "buffer count min: {}", portConfig.nBufferCountMin);
116 log->debug(TAG, "nBufferSize: {}", portConfig.nBufferSize);
117 log->debug(TAG, "bEnabled: {}", portConfig.bEnabled);
118 log->debug(TAG, "bPopulated: {}", portConfig.bPopulated);
119 log->debug(TAG, "eDomain: {}", portConfig.eDomain);
122 portConfig.nBufferCountActual = 1;
123 portConfig.nBufferSize = inputPortBufferSize;
124 portConfig.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
125 portConfig.format.video.eColorFormat = OMX_COLOR_Format32bitABGR8888;
126 portConfig.format.video.nFrameWidth = frameWidth;
127 portConfig.format.video.nStride = stride;
128 portConfig.format.video.nFrameHeight = frameHeight;
129 portConfig.format.video.nSliceHeight = sliceHeight;
131 // log->debug(TAG, "Setting buf count actual: {}, buf size: {}", portConfig.nBufferCountActual, portConfig.nBufferSize);
132 // log->debug(TAG, "calling setParameter: w {} h {} str {} sli {}", portConfig.format.video.nFrameWidth, portConfig.format.video.nFrameHeight,
133 // portConfig.format.video.nStride, portConfig.format.video.nSliceHeight);
135 #pragma GCC diagnostic push
136 #pragma GCC diagnostic ignored "-Wold-style-cast"
137 error = OMX_SetParameter(componentHandle, OMX_IndexParamPortDefinition, &portConfig);
138 #pragma GCC diagnostic pop
139 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_SetParameter in OMX_EGL_Render::prepareInputPort()", error);
141 // printPortSettings(false);
144 void OMX_EGL_Render::prepareOutputPort(EGLDisplay egldisplay)
146 OMX_PARAM_PORTDEFINITIONTYPE port_def_type;
147 memset(&port_def_type, 0, sizeof(port_def_type));
148 port_def_type.nSize = sizeof(port_def_type);
149 port_def_type.nVersion.nVersion = OMX_VERSION;
150 port_def_type.nPortIndex = outputPort;
152 #pragma GCC diagnostic push
153 #pragma GCC diagnostic ignored "-Wold-style-cast"
154 OMX_ERRORTYPE error = OMX_GetParameter(componentHandle, OMX_IndexParamPortDefinition, &port_def_type);
155 #pragma GCC diagnostic pop
156 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_GetParameter in OMX_EGL_Render::prep()", error);
158 port_def_type.nBufferCountActual = 1;
159 port_def_type.format.video.pNativeWindow = egldisplay;
161 #pragma GCC diagnostic push
162 #pragma GCC diagnostic ignored "-Wold-style-cast"
163 error = OMX_SetParameter(componentHandle, OMX_IndexParamPortDefinition, &port_def_type); // set port def: buffer count actual = 1
164 #pragma GCC diagnostic pop
165 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_SetParameter in OMX_EGL_Render::prep()", error);
168 void OMX_EGL_Render::allocateInputBuffers(char* data)
172 // log->debug(TAG, "Calling OMX_UseBuffer with data = {}", static_cast<void*>(data));
173 #pragma GCC diagnostic push
174 #pragma GCC diagnostic ignored "-Wold-style-cast"
175 OMX_ERRORTYPE error = OMX_UseBuffer(componentHandle, &inBuffer1, inputPort, static_cast<OMX_PTR>(0), inputPortBufferSize, reinterpret_cast<OMX_U8*>(data));
176 #pragma GCC diagnostic pop
177 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_UseBuffer in OMX_EGL_Render::allocateInputBuffers()", error);
180 log->debug(TAG, "OMX_UseBuffer:");
181 log->debug(TAG, " nSize = {}", inBuffer1->nSize);
182 log->debug(TAG, " pBuffer = {}", static_cast<void*>(inBuffer1->pBuffer));
183 log->debug(TAG, " nAllocLen = {}", inBuffer1->nAllocLen);
184 log->debug(TAG, " nFilledLen = {}", inBuffer1->nFilledLen);
185 log->debug(TAG, " nOffset = {}", inBuffer1->nOffset);
186 log->debug(TAG, " nInputPortIndex = {}", inBuffer1->nInputPortIndex);
187 log->debug(TAG, " nOutputPortIndex = {}", inBuffer1->nOutputPortIndex);
188 log->debug(TAG, " nFlags = {:#x}", inBuffer1->nFlags);
190 printPortSettings(false);
194 void OMX_EGL_Render::allocateEGLImageKHR(EGLImageKHR eglimagekhr)
196 #pragma GCC diagnostic push
197 #pragma GCC diagnostic ignored "-Wold-style-cast"
198 OMX_ERRORTYPE error = OMX_UseEGLImage(componentHandle, &eglRenderOutputBufferHeader, outputPort, this, static_cast<void*>(eglimagekhr));
199 #pragma GCC diagnostic pop
200 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_UseEGLImage in OMX_EGL_Render::allocateEGLImageKHR()", error);
202 // printPortSettings(true);
205 void OMX_EGL_Render::deallocateInputBuffers()
207 #pragma GCC diagnostic push
208 #pragma GCC diagnostic ignored "-Wold-style-cast"
209 OMX_ERRORTYPE error = OMX_FreeBuffer(componentHandle, inputPort, inBuffer1);
210 #pragma GCC diagnostic pop
211 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_FreeBuffer in OMX_EGL_Render::deallocateInputBuffers()", error);
216 void OMX_EGL_Render::deallocateEGLImageKHR()
218 #pragma GCC diagnostic push
219 #pragma GCC diagnostic ignored "-Wold-style-cast"
220 OMX_ERRORTYPE error = OMX_FreeBuffer(componentHandle, outputPort, eglRenderOutputBufferHeader);
221 #pragma GCC diagnostic pop
222 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_FreeBuffer in OMX_EGL_Render::deallocateEGLImageKHR()", error);
224 eglRenderOutputBufferHeader = NULL;
227 void OMX_EGL_Render::sendToInput(char* data, int dataSize)
229 // log->debug(TAG, "Starting sendToInput {}", dataSize);
231 inBuffer1->nFilledLen = dataSize;
232 inBuffer1->nOffset = 0;
233 inBuffer1->nTimeStamp = { 0, 0 };
234 inBuffer1->pAppPrivate = static_cast<OMX_PTR>(0);
235 inBuffer1->nFlags |= OMX_BUFFERFLAG_EOS;
236 inBuffer1->pBuffer = reinterpret_cast<OMX_U8*>(data);
238 // log->debug(TAG, "calling emptythisbuffer");
239 #pragma GCC diagnostic push
240 #pragma GCC diagnostic ignored "-Wold-style-cast"
241 OMX_ERRORTYPE error = OMX_EmptyThisBuffer(componentHandle, inBuffer1);
242 #pragma GCC diagnostic pop
243 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_EmptyThisBuffer in OMX_EGL_Render::sendToInput()", error);
244 // log->debug(TAG, "sendToInput done");
247 void OMX_EGL_Render::render()
249 struct BufferWithOutputPort* bufferWithOutputPort{};
253 bufferWithOutputPort = new BufferWithOutputPort();
254 bufferWithOutputPort->bufhead = eglRenderOutputBufferHeader;
255 eglRenderOutputBufferHeader->pAppPrivate = static_cast<OMX_PTR>(bufferWithOutputPort);
258 log->debug(TAG, "render: egl buffer header:");
259 log->debug(TAG, "{}", static_cast<void*>(eglRenderOutputBufferHeader->pBuffer));
260 log->debug(TAG, "{}", eglRenderOutputBufferHeader->nAllocLen);
261 log->debug(TAG, "{}", eglRenderOutputBufferHeader->nFilledLen);
262 log->debug(TAG, "{}", eglRenderOutputBufferHeader->nOffset);
263 log->debug(TAG, "{:#x}", eglRenderOutputBufferHeader->nFlags);
264 log->debug(TAG, "{}", eglRenderOutputBufferHeader->nInputPortIndex);
265 log->debug(TAG, "{}", eglRenderOutputBufferHeader->nOutputPortIndex);
266 log->debug(TAG, "{}", static_cast<void*>(eglRenderOutputBufferHeader->pAppPrivate));
269 std::unique_lock<std::mutex> ul(bufferWithOutputPort->mutex);
271 // log->debug(TAG, "calling fillthisbuffer. bufhead: {}, BufferWithOutput: {}", static_cast<void*>(eglRenderOutputBufferHeader), static_cast<void*>(bufferWithOutputPort));
273 #pragma GCC diagnostic push
274 #pragma GCC diagnostic ignored "-Wold-style-cast"
275 OMX_ERRORTYPE error = OMX_FillThisBuffer(componentHandle, eglRenderOutputBufferHeader);
276 #pragma GCC diagnostic pop
277 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_FillThisBuffer in OMX_EGL_Render::render()", error);
279 // log->debug(TAG, "done fillthisbuffer. bufhead: {}, BufferWithOutput: {}", static_cast<void*>(eglRenderOutputBufferHeader), static_cast<void*>(bufferWithOutputPort));
281 bufferWithOutputPort->cond.wait(ul, [bufferWithOutputPort] { return bufferWithOutputPort->done; });
285 log->debug(TAG, "receiveFromOutputPort signalled");
287 log->debug(TAG, "receiveFromOutput:");
288 log->debug(TAG, " nSize = {}", eglRenderOutputBufferHeader->nSize);
289 log->debug(TAG, " nAllocLen = {}", eglRenderOutputBufferHeader->nAllocLen);
290 log->debug(TAG, " nFilledLen = {}", eglRenderOutputBufferHeader->nFilledLen);
291 log->debug(TAG, " nOffset = {}", eglRenderOutputBufferHeader->nOffset);
292 log->debug(TAG, " nInputPortIndex = {}", eglRenderOutputBufferHeader->nInputPortIndex);
293 log->debug(TAG, " nOutputPortIndex = {}", eglRenderOutputBufferHeader->nOutputPortIndex);
294 log->debug(TAG, " nFlags = {:#x}", eglRenderOutputBufferHeader->nFlags);
297 delete bufferWithOutputPort;
298 bufferWithOutputPort = NULL;
302 if (bufferWithOutputPort)
304 free(bufferWithOutputPort);
305 bufferWithOutputPort = NULL;
311 void OMX_EGL_Render::printPortSettings(bool which)
313 OMX_PARAM_PORTDEFINITIONTYPE portSettings;
315 memset(&portSettings, 0, sizeof(portSettings));
316 portSettings.nSize = sizeof(portSettings);
317 portSettings.nVersion.nVersion = OMX_VERSION;
321 log->debug(TAG, "------ Port settings for OUTPUT:");
322 portSettings.nPortIndex = outputPort;
326 log->debug(TAG, "------ Port settings for INPUT:");
327 portSettings.nPortIndex = inputPort;
330 #pragma GCC diagnostic push
331 #pragma GCC diagnostic ignored "-Wold-style-cast"
332 OMX_ERRORTYPE error = OMX_GetParameter(componentHandle, OMX_IndexParamPortDefinition, &portSettings);
333 #pragma GCC diagnostic pop
334 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_GetParameter in OMX_EGL_Render::printPortSettings()", error);
336 log->debug(TAG, " nPortIndex: {}", portSettings.nPortIndex);
337 log->debug(TAG, " buffer count min, actual, size: {} {} {}", portSettings.nBufferCountMin, portSettings.nBufferCountActual, portSettings.nBufferSize);
338 log->debug(TAG, " eDir: {}", portSettings.eDir);
339 log->debug(TAG, " bEnabled: {}", portSettings.bEnabled);
340 log->debug(TAG, " bPopulated: {}", portSettings.bPopulated);
341 log->debug(TAG, " eDomain: {}", portSettings.eDomain);
343 log->debug(TAG, " cMIMEType: {}", static_cast<void*>(portSettings.format.video.cMIMEType));
344 log->debug(TAG, " pNativeRender: {}", static_cast<void*>(portSettings.format.video.pNativeRender));
345 log->debug(TAG, " nFrameWidth: {}", portSettings.format.video.nFrameWidth);
346 log->debug(TAG, " nFrameHeight: {}", portSettings.format.video.nFrameHeight);
347 log->debug(TAG, " nStride: {}", portSettings.format.video.nStride);
348 log->debug(TAG, " nSliceHeight: {}", portSettings.format.video.nSliceHeight);
349 log->debug(TAG, " nBitrate: {}", portSettings.format.video.nBitrate);
350 log->debug(TAG, " xFramerate: {}", portSettings.format.video.xFramerate);
351 log->debug(TAG, " eCompressionFormat: {:#x}", portSettings.format.video.eCompressionFormat);
352 log->debug(TAG, " eColorFormat: {:#x}", portSettings.format.video.eColorFormat);
355 OMX_ERRORTYPE OMX_EGL_Render::cb_EmptyBufferDone(OMX_IN OMX_HANDLETYPE /*hcomp*/, OMX_IN OMX_PTR /*appdata*/, OMX_IN OMX_BUFFERHEADERTYPE* /*buffer*/)
358 log->debug(TAG, "CB: EmptyBufferDone");
359 log->debug(TAG, " nSize = {}", buffer->nSize);
360 log->debug(TAG, " nAllocLen = {}", buffer->nAllocLen);
361 log->debug(TAG, " nFilledLen = {}", buffer->nFilledLen);
362 log->debug(TAG, " nOffset = {}", buffer->nOffset);
363 log->debug(TAG, " nInputPortIndex = {}", buffer->nInputPortIndex);
364 log->debug(TAG, " nOutputPortIndex = {}", buffer->nOutputPortIndex);
365 log->debug(TAG, " nFlags = {:#x}", buffer->nFlags);
367 return OMX_ErrorNone;
370 OMX_ERRORTYPE OMX_EGL_Render::cb_FillBufferDone(OMX_IN OMX_HANDLETYPE /*hcomp*/, OMX_IN OMX_PTR /*appdata*/, OMX_IN OMX_BUFFERHEADERTYPE* buffer)
372 // log->debug(TAG, "CB: FillBufferDone, handle: {}, appdata: {}, buffer: {}", static_cast<void*>(hcomp), static_cast<void*>(appdata), static_cast<void*>(buffer));
374 struct BufferWithOutputPort* bufferWithOutputPort = static_cast<struct BufferWithOutputPort*>(buffer->pAppPrivate);
375 bufferWithOutputPort->mutex.lock();
376 bufferWithOutputPort->done = true;
377 bufferWithOutputPort->mutex.unlock();
378 bufferWithOutputPort->cond.notify_one();
380 return OMX_ErrorNone;