]> git.vomp.tv Git - vompclient.git/blob - omx/omxeglrender.cc
61 CWFs
[vompclient.git] / omx / omxeglrender.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 <VG/openvg.h>
21 #include <EGL/egl.h>
22 #include <EGL/eglext.h>
23
24 #include "../log.h"
25
26 #include "omxeglrender.h"
27
28 static const char* TAG = "OMX_EGL_Render";
29
30
31 OMX_EGL_Render::OMX_EGL_Render()
32 {
33   omx_egl_render = this;
34 }
35
36 OMX_EGL_Render::~OMX_EGL_Render()
37 {
38   omx_image_decode = NULL;
39   handle_egl_render = 0;
40 }
41
42 bool OMX_EGL_Render::init()
43 {
44   initEventsProcessing();
45
46   OMX_CALLBACKTYPE callbacks = {&scb_EventHandler, &scb_EmptyBufferDone, &scb_FillBufferDone};
47
48   char* componentName;
49   asprintf(&componentName, "%s", componentName_egl_render);
50   OMX_ERRORTYPE error = OMX_GetHandle(&componentHandle, componentName, NULL, &callbacks);
51   free(componentName);
52 //   log->debug(TAG, "HANDLE ALLOC: OMX_EGL_Render: {} error: {:#x}", static_cast<void*>(componentHandle), error);
53   if (error != OMX_ErrorNone) return false;
54
55   handle_egl_render = componentHandle;
56
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;
61
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;
67
68   inputPort = p_param.nStartPortNumber;
69   outputPort = p_param.nStartPortNumber + 1;
70
71 //   log->debug(TAG, "IN: {}, OUT: {}", inputPort, outputPort);
72   return true;
73 }
74
75 void OMX_EGL_Render::shutdown()
76 {
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);
80 }
81
82 void OMX_EGL_Render::prepareInputPort(OMX_U32 frameWidth, OMX_U32 frameHeight, OMX_U32 stride)
83 {
84 //   log->debug(TAG, "prepareInputPort");
85
86   // Calculate a slice height. It must be divisible by 16 and >= frameHeight
87   // Temporarily use sliceHeight for remainder
88   int sliceHeight = frameHeight % 16;
89   if (sliceHeight == 0)
90     sliceHeight = frameHeight;
91   else
92     sliceHeight = frameHeight + 16 - sliceHeight;
93
94   // Buffer size IS THE SLICE HEIGHT multiplied by the stride
95   inputPortBufferSize = sliceHeight * stride;
96
97
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;
103
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);
109
110   /*
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);
120   */
121
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;
130
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);
134
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);
140
141 //   printPortSettings(false);
142 }
143
144 void OMX_EGL_Render::prepareOutputPort(EGLDisplay egldisplay)
145 {
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;
151
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);
157
158   port_def_type.nBufferCountActual = 1;
159   port_def_type.format.video.pNativeWindow = egldisplay;
160
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);
166 }
167
168 void OMX_EGL_Render::allocateInputBuffers(char* data)
169 {
170   inBuffer1 = NULL;
171
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);
178
179   /*
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);
189
190   printPortSettings(false);
191   */
192 }
193
194 void OMX_EGL_Render::allocateEGLImageKHR(EGLImageKHR eglimagekhr)
195 {
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);
201
202 //   printPortSettings(true);
203 }
204
205 void OMX_EGL_Render::deallocateInputBuffers()
206 {
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);
212
213   inBuffer1 = NULL;
214 }
215
216 void OMX_EGL_Render::deallocateEGLImageKHR()
217 {
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);
223
224   eglRenderOutputBufferHeader = NULL;
225 }
226
227 void OMX_EGL_Render::sendToInput(char* data, int dataSize)
228 {
229 //   log->debug(TAG, "Starting sendToInput {}", dataSize);
230
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);
237
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");
245 }
246
247 void OMX_EGL_Render::render()
248 {
249   struct BufferWithOutputPort* bufferWithOutputPort{};
250
251   try
252   {
253     bufferWithOutputPort = new BufferWithOutputPort();
254     bufferWithOutputPort->bufhead = eglRenderOutputBufferHeader;
255     eglRenderOutputBufferHeader->pAppPrivate = static_cast<OMX_PTR>(bufferWithOutputPort);
256
257     /*
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));
267     */
268
269     std::unique_lock<std::mutex> ul(bufferWithOutputPort->mutex);
270
271 //     log->debug(TAG, "calling fillthisbuffer. bufhead: {}, BufferWithOutput: {}", static_cast<void*>(eglRenderOutputBufferHeader), static_cast<void*>(bufferWithOutputPort));
272
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);
278
279 //     log->debug(TAG, "done fillthisbuffer. bufhead: {}, BufferWithOutput: {}", static_cast<void*>(eglRenderOutputBufferHeader), static_cast<void*>(bufferWithOutputPort));
280
281     bufferWithOutputPort->cond.wait(ul, [bufferWithOutputPort] { return bufferWithOutputPort->done; });
282     ul.unlock();
283
284     /*
285     log->debug(TAG, "receiveFromOutputPort signalled");
286
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);
295     */
296
297     delete bufferWithOutputPort;
298     bufferWithOutputPort = NULL;
299   }
300   catch(...)
301   {
302     if (bufferWithOutputPort)
303     {
304       free(bufferWithOutputPort);
305       bufferWithOutputPort = NULL;
306     }
307     throw;
308   }
309 }
310
311 void OMX_EGL_Render::printPortSettings(bool which)
312 {
313   OMX_PARAM_PORTDEFINITIONTYPE portSettings;
314
315   memset(&portSettings, 0, sizeof(portSettings));
316   portSettings.nSize = sizeof(portSettings);
317   portSettings.nVersion.nVersion = OMX_VERSION;
318
319   if (which)
320   {
321     log->debug(TAG, "------ Port settings for OUTPUT:");
322     portSettings.nPortIndex = outputPort;
323   }
324   else
325   {
326     log->debug(TAG, "------ Port settings for INPUT:");
327     portSettings.nPortIndex = inputPort;
328   }
329
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);
335
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);
342
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);
353 }
354
355 OMX_ERRORTYPE OMX_EGL_Render::cb_EmptyBufferDone(OMX_IN OMX_HANDLETYPE /*hcomp*/, OMX_IN OMX_PTR /*appdata*/, OMX_IN OMX_BUFFERHEADERTYPE* /*buffer*/)
356 {
357   /*
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);
366   */
367   return OMX_ErrorNone;
368 }
369
370 OMX_ERRORTYPE OMX_EGL_Render::cb_FillBufferDone(OMX_IN OMX_HANDLETYPE /*hcomp*/, OMX_IN OMX_PTR /*appdata*/, OMX_IN OMX_BUFFERHEADERTYPE* buffer)
371 {
372 //   log->debug(TAG, "CB: FillBufferDone, handle: {}, appdata: {}, buffer: {}", static_cast<void*>(hcomp), static_cast<void*>(appdata), static_cast<void*>(buffer));
373
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();
379
380   return OMX_ErrorNone;
381 }