]> git.vomp.tv Git - vompclient.git/blob - omx/omximagedecode.cc
Disable copious logging from new ImageOMX code
[vompclient.git] / omx / omximagedecode.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
22 #include "omximagedecode.h"
23
24 static const char* TAG = "OMX_Image_Decode";
25
26 OMX_Image_Decode::OMX_Image_Decode()
27 {
28   omx_image_decode = this;
29 }
30
31 OMX_Image_Decode::~OMX_Image_Decode()
32 {
33   omx_image_decode = NULL;
34   handle_image_decode = 0;
35 }
36
37 bool OMX_Image_Decode::init()
38 {
39   initEventsProcessing();
40
41   OMX_CALLBACKTYPE callbacks = {&scb_EventHandler, &scb_EmptyBufferDone, &scb_FillBufferDone};
42
43   char* componentName;
44   asprintf(&componentName, "%s", componentName_image_decode);
45   OMX_ERRORTYPE error = OMX_GetHandle(&componentHandle, componentName, NULL, &callbacks);
46   free(componentName);
47 //   log->debug(TAG, "HANDLE ALLOC: omx_image_decode: {}", static_cast<void*>(componentHandle));
48   if (error != OMX_ErrorNone) return false;
49
50   handle_image_decode = componentHandle;
51
52   OMX_PORT_PARAM_TYPE p_param;
53   memset(&p_param, 0, sizeof(p_param));
54   p_param.nSize = sizeof(p_param);
55   p_param.nVersion.nVersion = OMX_VERSION;
56
57   error = OMX_GetParameter(componentHandle, OMX_IndexParamImageInit, &p_param);
58   if (error != OMX_ErrorNone) return false;
59
60   inputPort = p_param.nStartPortNumber;
61   outputPort = p_param.nStartPortNumber + 1;
62
63 //   log->debug(TAG, "IN: {}, OUT: {}", inputPort, outputPort);
64   return true;
65 }
66
67 void OMX_Image_Decode::shutdown()
68 {
69   stopEventsProcessing();
70   OMX_ERRORTYPE error = OMX_FreeHandle(componentHandle);
71   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_FreeHandle in OMX_Image_Decode::shutdown()", error);
72 }
73
74 void OMX_Image_Decode::prepareInputBuffers(int tdataSize)
75 {
76   dataSize = tdataSize;
77
78   OMX_PARAM_PORTDEFINITIONTYPE port_def_type;
79   memset(&port_def_type, 0, sizeof(port_def_type));
80   port_def_type.nSize = sizeof(port_def_type);
81   port_def_type.nVersion.nVersion = OMX_VERSION;
82   port_def_type.nPortIndex = inputPort;
83
84   OMX_ERRORTYPE error = OMX_GetParameter(componentHandle, OMX_IndexParamPortDefinition, &port_def_type);
85   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_GetParameter in OMX_Image_Decode::prepareInputBuffers()", error);
86
87 //   log->debug(TAG, "Defaults: bufferCountActual: {}, bufferCountMin: {}, nBufferSize: {}",
88 //         port_def_type.nBufferCountActual, port_def_type.nBufferCountMin, port_def_type.nBufferSize);
89
90   port_def_type.nBufferCountActual = port_def_type.nBufferCountMin;
91   if (dataSize > port_def_type.nBufferSize) port_def_type.nBufferSize = dataSize;
92
93 //   log->debug(TAG, "Setting buf count actual: {}, buf size: {}",
94 //         port_def_type.nBufferCountActual, port_def_type.nBufferSize);
95
96   error = OMX_SetParameter(componentHandle, OMX_IndexParamPortDefinition, &port_def_type);
97   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_SetParameter in OMX_Image_Decode::prepareInputBuffers()", error);
98 }
99
100 void OMX_Image_Decode::setFormat()
101 {
102   OMX_IMAGE_PARAM_PORTFORMATTYPE ft_type;
103   memset(&ft_type, 0, sizeof(ft_type));
104   ft_type.nSize = sizeof(ft_type);
105   ft_type.nVersion.nVersion = OMX_VERSION;
106   ft_type.eCompressionFormat = OMX_IMAGE_CodingPNG;
107   ft_type.nPortIndex = inputPort;
108
109   // Would use this function to select between PNG and JPEG but image_decode
110   // only outputs JPEG decoded images in YUV420, because of course it does.
111   // ft_type.eCompressionFormat = OMX_IMAGE_CodingJPEG;
112
113   OMX_ERRORTYPE error = OMX_SetParameter(componentHandle, OMX_IndexParamImagePortFormat, &ft_type);
114   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_SetParameter in OMX_Image_Decode::setFormat()", error);
115 //   log->debug(TAG, "setFormat OK");
116 }
117
118 void OMX_Image_Decode::setSliceHeight(int newSliceHeight)
119 {
120   outputPortSettings.format.image.nSliceHeight = newSliceHeight;
121 //   log->debug(TAG, "nSliceHeight: {}", outputPortSettings.format.image.nSliceHeight);
122
123   OMX_ERRORTYPE error = OMX_SetParameter(componentHandle, OMX_IndexParamPortDefinition, &outputPortSettings);
124   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_SetParameter in OMX_Image_Decode::setSliceHeight()", error);
125
126   /*
127   {
128     // Dump new independant output settings
129     OMX_PARAM_PORTDEFINITIONTYPE indTest;
130     memset(&indTest, 0, sizeof(indTest));
131     indTest.nSize = sizeof(indTest);
132     indTest.nVersion.nVersion = OMX_VERSION;
133     indTest.nPortIndex = outputPort;
134
135     error = OMX_GetParameter(componentHandle, OMX_IndexParamPortDefinition, &indTest);
136     if (error != OMX_ErrorNone) throw OMX_Exception("OMX_GetParameter in OMX_Image_Decode::setSliceHeight()", error);
137
138     log->debug(TAG, "Port def type from outputPort");
139     log->debug(TAG, "buffer count actual: {}", indTest.nBufferCountActual);
140     log->debug(TAG, "eDir: {}", indTest.eDir);
141     log->debug(TAG, "nBufferSize: {}", indTest.nBufferSize);
142     log->debug(TAG, "bEnabled: {}", indTest.bEnabled);
143     log->debug(TAG, "bPopulated: {}", indTest.bPopulated);
144     log->debug(TAG, "eDomain: {}", indTest.eDomain);
145
146     log->debug(TAG, "cMIMEType: {}", static_cast<void*>(indTest.format.image.cMIMEType));
147     log->debug(TAG, "pNativeRender: {}", static_cast<void*>(indTest.format.image.pNativeRender));
148     log->debug(TAG, "nFrameWidth: {}", indTest.format.image.nFrameWidth);
149     log->debug(TAG, "nFrameHeight: {}", indTest.format.image.nFrameHeight);
150     log->debug(TAG, "nStride: {}", indTest.format.image.nStride);
151     log->debug(TAG, "nSliceHeight: {}", indTest.format.image.nSliceHeight);
152     log->debug(TAG, "eColorFormat: {:#x}", indTest.format.image.eColorFormat);
153   }
154   */
155 }
156
157 void OMX_Image_Decode::allocateInputBuffers(char* data)
158 {
159   inBuffer1 = NULL;
160   inBuffer2 = NULL;
161
162 //   log->debug(TAG, "Calling OMX_UseBuffer");
163   OMX_ERRORTYPE error = OMX_UseBuffer(componentHandle, &inBuffer1, inputPort, static_cast<OMX_PTR>(0), dataSize, reinterpret_cast<OMX_U8*>(data));
164   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_UseBuffer 1 in OMX_Image_Decode::allocateInputBuffers()", error);
165
166   // Hardcoded assumption - image_decode has min 2 input buffers
167   error = OMX_UseBuffer(componentHandle, &inBuffer2, inputPort, static_cast<OMX_PTR>(0), 0, NULL);
168   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_UseBuffer 2 in OMX_Image_Decode::allocateInputBuffers()", error);
169 }
170
171 void OMX_Image_Decode::allocateOutputBuffer()
172 {
173   OMX_ERRORTYPE error = OMX_UseBuffer(componentHandle, &outputBufferHeader, outputPort, static_cast<OMX_PTR>(0), outputPortSettings.nBufferSize, (OMX_U8*)NULL);
174   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_UseBuffer in OMX_Image_Decode::allocateOutputBuffer()", error);
175 }
176
177 void OMX_Image_Decode::deallocateInputBuffers()
178 {
179   OMX_ERRORTYPE error = OMX_FreeBuffer(componentHandle, inputPort, inBuffer1);
180   inBuffer1 = NULL;
181   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_FreeBuffer 1 in OMX_Image_Decode::deallocateInputBuffers()", error);
182
183   error = OMX_FreeBuffer(componentHandle, inputPort, inBuffer2);
184   inBuffer2 = NULL;
185   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_FreeBuffer 2 in OMX_Image_Decode::deallocateInputBuffers()", error);
186 }
187
188 void OMX_Image_Decode::deallocateOutputBuffer()
189 {
190   OMX_ERRORTYPE error = OMX_FreeBuffer(componentHandle, outputPort, outputBufferHeader);
191   outputBufferHeader = NULL;
192   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_FreeBuffer in OMX_Image_Decode::deallocateOutputBuffer()", error);
193 }
194
195 void OMX_Image_Decode::sendToInput()
196 {
197 //   log->debug(TAG, "Starting sendToInput");
198   inBuffer1->nFilledLen = dataSize;
199   inBuffer1->nOffset = 0;
200   inBuffer1->nTimeStamp = { 0, 0 };
201   inBuffer1->pAppPrivate = static_cast<OMX_PTR>(0);
202   inBuffer1->nFlags |= OMX_BUFFERFLAG_EOS;
203
204 //   log->debug(TAG, "calling emptythisbuffer");
205   OMX_ERRORTYPE error = OMX_EmptyThisBuffer(componentHandle, inBuffer1);
206   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_EmptyThisBuffer in OMX_Image_Decode::sendToInput()", error);
207 //   log->debug(TAG, "sendToInput done");
208 }
209
210 void OMX_Image_Decode::waitForOutputPortSettingsChange()
211 {
212   eventsProcessorMutex.lock();
213   std::unique_lock<std::mutex> ul(eventWaitersMutex);
214
215   EventWaiter* eventWaiter = new EventWaiter();
216   eventWaiter->waiting = true;
217   eventWaiter->eventType = OMX_EventPortSettingsChanged;
218   eventWaiter->port = outputPort;
219   eventWaiters.push_back(eventWaiter);
220
221   eventsProcessorWake = true;
222   eventsProcessorMutex.unlock();
223   eventsProcessorCond.notify_one();
224
225   eventWaiter->cond.wait(ul);  // sleep this thread
226   ul.unlock();
227
228   if (!eventWaiter->receivedEvent)
229   {
230     delete eventWaiter;
231     throw OMX_Exception("Error waiting for event in waitForOutputPortSettingsChange", 0);
232   }
233
234   // The event processor thread received an event and saved it here
235 //   log->debug(TAG, "received outputportsettingschanged event!");
236   delete eventWaiter->receivedEvent;
237   delete eventWaiter;
238
239   memset(&outputPortSettings, 0, sizeof(outputPortSettings));
240   outputPortSettings.nSize = sizeof(outputPortSettings);
241   outputPortSettings.nVersion.nVersion = OMX_VERSION;
242   outputPortSettings.nPortIndex = outputPort;
243   OMX_ERRORTYPE error = OMX_GetParameter(componentHandle, OMX_IndexParamPortDefinition, &outputPortSettings);
244   if (error != OMX_ErrorNone) throw OMX_Exception("OMX_GetParameter in OMX_Image_Decode::waitForOutputPortSettingsChange()", error);
245
246 /*
247   log->debug(TAG, "Port def type from outputPort");
248   log->debug(TAG, "buffer count actual: {}", outputPortSettings.nBufferCountActual);
249   log->debug(TAG, "eDir: {}", outputPortSettings.eDir);
250   log->debug(TAG, "nBufferSize: {}", outputPortSettings.nBufferSize);
251   log->debug(TAG, "bEnabled: {}", outputPortSettings.bEnabled);
252   log->debug(TAG, "bPopulated: {}", outputPortSettings.bPopulated);
253   log->debug(TAG, "eDomain: {}", outputPortSettings.eDomain);
254
255   log->debug(TAG, "cMIMEType: {}", static_cast<void*>(outputPortSettings.format.image.cMIMEType));
256   log->debug(TAG, "pNativeRender: {}", static_cast<void*>(outputPortSettings.format.image.pNativeRender));
257   log->debug(TAG, "nFrameWidth: {}", outputPortSettings.format.image.nFrameWidth);
258   log->debug(TAG, "nFrameHeight: {}", outputPortSettings.format.image.nFrameHeight);
259   log->debug(TAG, "nStride: {}", outputPortSettings.format.image.nStride);
260   log->debug(TAG, "nSliceHeight: {}", outputPortSettings.format.image.nSliceHeight);
261   */
262 }
263
264 void OMX_Image_Decode::receiveFromOutput(char** data, int* nFlags)
265 {
266   void* outputBufferMem{};
267
268   try
269   {
270     outputBufferMem = malloc(outputPortSettings.nBufferSize);
271     memset(outputBufferMem, 0, outputPortSettings.nBufferSize);
272     outputBufferHeader->pBuffer = static_cast<OMX_U8*>(outputBufferMem);
273
274     struct BufferWithOutputPort* bufferWithOutputPort = new BufferWithOutputPort();
275     bufferWithOutputPort->bufhead = outputBufferHeader;
276     outputBufferHeader->pAppPrivate = static_cast<OMX_PTR>(bufferWithOutputPort);
277
278     std::unique_lock<std::mutex> ul(bufferWithOutputPort->mutex);
279
280 //     log->debug(TAG, "calling fillthisbuffer. bufhead: {}, BufferWithOutput: {}", static_cast<void*>(outputBufferHeader), static_cast<void*>(bufferWithOutputPort));
281
282     OMX_ERRORTYPE error;
283
284     error = OMX_FillThisBuffer(componentHandle, outputBufferHeader);
285     if (error != OMX_ErrorNone) throw OMX_Exception("OMX_FillThisBuffer in OMX_Image_Decode::receiveFromOutput()", error);
286
287 //     log->debug(TAG, "called fillthisbuffer. bufsize = {}", outputPortSettings.nBufferSize);
288
289     bufferWithOutputPort->cond.wait(ul, [bufferWithOutputPort] { return bufferWithOutputPort->done; });
290     ul.unlock();
291
292 //     log->debug(TAG, "receiveFromOutputPort signalled");
293
294     *data = static_cast<char*>(outputBufferMem); // caller takes ownership
295     *nFlags = outputBufferHeader->nFlags;
296
297     outputBufferMem = NULL;
298
299     // The slice height is all important - can't trust nFilledLen
300
301     /*
302     log->debug(TAG, "receiveFromOutput:");
303     log->debug(TAG, "  nSize = {}", outputBufferHeader->nSize);
304     log->debug(TAG, "  nAllocLen = {}", outputBufferHeader->nAllocLen);
305     log->debug(TAG, "  nFilledLen = {}", outputBufferHeader->nFilledLen);
306     log->debug(TAG, "  nOffset = {}", outputBufferHeader->nOffset);
307     log->debug(TAG, "  nInputPortIndex = {}", outputBufferHeader->nInputPortIndex);
308     log->debug(TAG, "  nOutputPortIndex = {}", outputBufferHeader->nOutputPortIndex);
309     log->debug(TAG, "  nFlags = {:#x}", outputBufferHeader->nFlags);
310     */
311
312     delete bufferWithOutputPort;
313   }
314   catch(...)
315   {
316     if (outputBufferMem)
317     {
318       free(outputBufferMem);
319       outputBufferMem = NULL;
320     }
321     throw;
322   }
323 }
324
325 void OMX_Image_Decode::getImageInfo(int* width, int* height, int* stride, int* sliceHeight)
326 {
327   *width = outputPortSettings.format.image.nFrameWidth;
328   *height = outputPortSettings.format.image.nFrameHeight;
329   *stride = outputPortSettings.format.image.nStride;
330   *sliceHeight = outputPortSettings.format.image.nSliceHeight;
331 }
332
333 OMX_ERRORTYPE OMX_Image_Decode::cb_EmptyBufferDone(OMX_IN OMX_HANDLETYPE /*hcomp*/, OMX_IN OMX_PTR /*appdata*/, OMX_IN OMX_BUFFERHEADERTYPE* buffer)
334 {
335   /*
336   log->debug(TAG, "CB: EmptyBufferDone");
337   log->debug(TAG, "  nSize = {}", buffer->nSize);
338   log->debug(TAG, "  nAllocLen = {}", buffer->nAllocLen);
339   log->debug(TAG, "  nFilledLen = {}", buffer->nFilledLen);
340   log->debug(TAG, "  nOffset = {}", buffer->nOffset);
341   log->debug(TAG, "  nInputPortIndex = {}", buffer->nInputPortIndex);
342   log->debug(TAG, "  nOutputPortIndex = {}", buffer->nOutputPortIndex);
343   log->debug(TAG, "  nFlags = {:#x}", buffer->nFlags);
344   */
345   return OMX_ErrorNone;
346 }
347
348 OMX_ERRORTYPE OMX_Image_Decode::cb_FillBufferDone(OMX_IN OMX_HANDLETYPE hcomp, OMX_IN OMX_PTR appdata, OMX_IN OMX_BUFFERHEADERTYPE* buffer)
349 {
350 //   log->debug(TAG, "CB: FillBufferDone, handle: {}, appdata: {}, buffer: {}", static_cast<void*>(hcomp), static_cast<void*>(appdata), static_cast<void*>(buffer));
351
352   struct BufferWithOutputPort* bufferWithOutputPort = static_cast<struct BufferWithOutputPort*>(buffer->pAppPrivate);
353   bufferWithOutputPort->mutex.lock();
354   bufferWithOutputPort->done = true;
355   bufferWithOutputPort->mutex.unlock();
356   bufferWithOutputPort->cond.notify_one();
357
358   return OMX_ErrorNone;
359 }