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/>.
22 #include "omximagedecode.h"
24 static const char* TAG = "OMX_Image_Decode";
26 OMX_Image_Decode::OMX_Image_Decode()
28 omx_image_decode = this;
31 OMX_Image_Decode::~OMX_Image_Decode()
33 omx_image_decode = NULL;
34 handle_image_decode = 0;
37 bool OMX_Image_Decode::init()
39 initEventsProcessing();
41 OMX_CALLBACKTYPE callbacks = {&scb_EventHandler, &scb_EmptyBufferDone, &scb_FillBufferDone};
44 asprintf(&componentName, "%s", componentName_image_decode);
45 OMX_ERRORTYPE error = OMX_GetHandle(&componentHandle, componentName, NULL, &callbacks);
47 log->debug(TAG, "HANDLE ALLOC: omx_image_decode: {}", static_cast<void*>(componentHandle));
48 if (error != OMX_ErrorNone) return false;
50 handle_image_decode = componentHandle;
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;
57 error = OMX_GetParameter(componentHandle, OMX_IndexParamImageInit, &p_param);
58 if (error != OMX_ErrorNone) return false;
60 inputPort = p_param.nStartPortNumber;
61 outputPort = p_param.nStartPortNumber + 1;
63 log->debug(TAG, "IN: {}, OUT: {}", inputPort, outputPort);
67 void OMX_Image_Decode::shutdown()
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);
74 void OMX_Image_Decode::prepareInputBuffers(int tdataSize)
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;
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);
87 log->debug(TAG, "Defaults: bufferCountActual: {}, bufferCountMin: {}, nBufferSize: {}",
88 port_def_type.nBufferCountActual, port_def_type.nBufferCountMin, port_def_type.nBufferSize);
90 port_def_type.nBufferCountActual = port_def_type.nBufferCountMin;
91 if (dataSize > port_def_type.nBufferSize) port_def_type.nBufferSize = dataSize;
93 log->debug(TAG, "Setting buf count actual: {}, buf size: {}",
94 port_def_type.nBufferCountActual, port_def_type.nBufferSize);
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);
100 void OMX_Image_Decode::setFormat()
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;
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;
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");
118 void OMX_Image_Decode::setSliceHeight(int newSliceHeight)
120 outputPortSettings.format.image.nSliceHeight = newSliceHeight;
121 log->debug(TAG, "nSliceHeight: {}", outputPortSettings.format.image.nSliceHeight);
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);
127 // Dump new independant output settings
128 OMX_PARAM_PORTDEFINITIONTYPE indTest;
129 memset(&indTest, 0, sizeof(indTest));
130 indTest.nSize = sizeof(indTest);
131 indTest.nVersion.nVersion = OMX_VERSION;
132 indTest.nPortIndex = outputPort;
134 error = OMX_GetParameter(componentHandle, OMX_IndexParamPortDefinition, &indTest);
135 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_GetParameter in OMX_Image_Decode::setSliceHeight()", error);
137 log->debug(TAG, "Port def type from outputPort");
138 log->debug(TAG, "buffer count actual: {}", indTest.nBufferCountActual);
139 log->debug(TAG, "eDir: {}", indTest.eDir);
140 log->debug(TAG, "nBufferSize: {}", indTest.nBufferSize);
141 log->debug(TAG, "bEnabled: {}", indTest.bEnabled);
142 log->debug(TAG, "bPopulated: {}", indTest.bPopulated);
143 log->debug(TAG, "eDomain: {}", indTest.eDomain);
145 log->debug(TAG, "cMIMEType: {}", static_cast<void*>(indTest.format.image.cMIMEType));
146 log->debug(TAG, "pNativeRender: {}", static_cast<void*>(indTest.format.image.pNativeRender));
147 log->debug(TAG, "nFrameWidth: {}", indTest.format.image.nFrameWidth);
148 log->debug(TAG, "nFrameHeight: {}", indTest.format.image.nFrameHeight);
149 log->debug(TAG, "nStride: {}", indTest.format.image.nStride);
150 log->debug(TAG, "nSliceHeight: {}", indTest.format.image.nSliceHeight);
151 log->debug(TAG, "eColorFormat: {:#x}", indTest.format.image.eColorFormat);
155 void OMX_Image_Decode::allocateInputBuffers(char* data)
160 log->debug(TAG, "Calling OMX_UseBuffer");
161 OMX_ERRORTYPE error = OMX_UseBuffer(componentHandle, &inBuffer1, inputPort, static_cast<OMX_PTR>(0), dataSize, reinterpret_cast<OMX_U8*>(data));
162 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_UseBuffer 1 in OMX_Image_Decode::allocateInputBuffers()", error);
164 // Hardcoded assumption - image_decode has min 2 input buffers
165 error = OMX_UseBuffer(componentHandle, &inBuffer2, inputPort, static_cast<OMX_PTR>(0), 0, NULL);
166 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_UseBuffer 2 in OMX_Image_Decode::allocateInputBuffers()", error);
169 void OMX_Image_Decode::allocateOutputBuffer()
171 OMX_ERRORTYPE error = OMX_UseBuffer(componentHandle, &outputBufferHeader, outputPort, static_cast<OMX_PTR>(0), outputPortSettings.nBufferSize, (OMX_U8*)NULL);
172 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_UseBuffer in OMX_Image_Decode::allocateOutputBuffer()", error);
175 void OMX_Image_Decode::deallocateInputBuffers()
177 OMX_ERRORTYPE error = OMX_FreeBuffer(componentHandle, inputPort, inBuffer1);
179 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_FreeBuffer 1 in OMX_Image_Decode::deallocateInputBuffers()", error);
181 error = OMX_FreeBuffer(componentHandle, inputPort, inBuffer2);
183 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_FreeBuffer 2 in OMX_Image_Decode::deallocateInputBuffers()", error);
186 void OMX_Image_Decode::deallocateOutputBuffer()
188 OMX_ERRORTYPE error = OMX_FreeBuffer(componentHandle, outputPort, outputBufferHeader);
189 outputBufferHeader = NULL;
190 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_FreeBuffer in OMX_Image_Decode::deallocateOutputBuffer()", error);
193 void OMX_Image_Decode::sendToInput()
195 log->debug(TAG, "Starting sendToInput");
196 inBuffer1->nFilledLen = dataSize;
197 inBuffer1->nOffset = 0;
198 inBuffer1->nTimeStamp = { 0, 0 };
199 inBuffer1->pAppPrivate = static_cast<OMX_PTR>(0);
200 inBuffer1->nFlags |= OMX_BUFFERFLAG_EOS;
202 log->debug(TAG, "calling emptythisbuffer");
203 OMX_ERRORTYPE error = OMX_EmptyThisBuffer(componentHandle, inBuffer1);
204 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_EmptyThisBuffer in OMX_Image_Decode::sendToInput()", error);
205 log->debug(TAG, "sendToInput done");
208 void OMX_Image_Decode::waitForOutputPortSettingsChange()
210 eventsProcessorMutex.lock();
211 std::unique_lock<std::mutex> ul(eventWaitersMutex);
213 EventWaiter* eventWaiter = new EventWaiter();
214 eventWaiter->waiting = true;
215 eventWaiter->eventType = OMX_EventPortSettingsChanged;
216 eventWaiter->port = outputPort;
217 eventWaiters.push_back(eventWaiter);
219 eventsProcessorWake = true;
220 eventsProcessorMutex.unlock();
221 eventsProcessorCond.notify_one();
223 eventWaiter->cond.wait(ul); // sleep this thread
226 if (!eventWaiter->receivedEvent)
229 throw OMX_Exception("Error waiting for event in waitForOutputPortSettingsChange", 0);
232 // The event processor thread received an event and saved it here
233 log->debug(TAG, "received outputportsettingschanged event!");
234 delete eventWaiter->receivedEvent;
237 memset(&outputPortSettings, 0, sizeof(outputPortSettings));
238 outputPortSettings.nSize = sizeof(outputPortSettings);
239 outputPortSettings.nVersion.nVersion = OMX_VERSION;
240 outputPortSettings.nPortIndex = outputPort;
242 OMX_ERRORTYPE error = OMX_GetParameter(componentHandle, OMX_IndexParamPortDefinition, &outputPortSettings);
243 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_GetParameter in OMX_Image_Decode::waitForOutputPortSettingsChange()", error);
245 log->debug(TAG, "Port def type from outputPort");
246 log->debug(TAG, "buffer count actual: {}", outputPortSettings.nBufferCountActual);
247 log->debug(TAG, "eDir: {}", outputPortSettings.eDir);
248 log->debug(TAG, "nBufferSize: {}", outputPortSettings.nBufferSize);
249 log->debug(TAG, "bEnabled: {}", outputPortSettings.bEnabled);
250 log->debug(TAG, "bPopulated: {}", outputPortSettings.bPopulated);
251 log->debug(TAG, "eDomain: {}", outputPortSettings.eDomain);
253 log->debug(TAG, "cMIMEType: {}", static_cast<void*>(outputPortSettings.format.image.cMIMEType));
254 log->debug(TAG, "pNativeRender: {}", static_cast<void*>(outputPortSettings.format.image.pNativeRender));
255 log->debug(TAG, "nFrameWidth: {}", outputPortSettings.format.image.nFrameWidth);
256 log->debug(TAG, "nFrameHeight: {}", outputPortSettings.format.image.nFrameHeight);
257 log->debug(TAG, "nStride: {}", outputPortSettings.format.image.nStride);
258 log->debug(TAG, "nSliceHeight: {}", outputPortSettings.format.image.nSliceHeight);
261 void OMX_Image_Decode::receiveFromOutput(char** data, int* nFlags)
263 void* outputBufferMem{};
267 outputBufferMem = malloc(outputPortSettings.nBufferSize);
268 memset(outputBufferMem, 0, outputPortSettings.nBufferSize);
269 outputBufferHeader->pBuffer = static_cast<OMX_U8*>(outputBufferMem);
271 struct BufferWithOutputPort* bufferWithOutputPort = new BufferWithOutputPort();
272 bufferWithOutputPort->bufhead = outputBufferHeader;
273 outputBufferHeader->pAppPrivate = static_cast<OMX_PTR>(bufferWithOutputPort);
275 std::unique_lock<std::mutex> ul(bufferWithOutputPort->mutex);
277 log->debug(TAG, "calling fillthisbuffer. bufhead: {}, BufferWithOutput: {}", static_cast<void*>(outputBufferHeader), static_cast<void*>(bufferWithOutputPort));
281 error = OMX_FillThisBuffer(componentHandle, outputBufferHeader);
282 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_FillThisBuffer in OMX_Image_Decode::receiveFromOutput()", error);
284 log->debug(TAG, "called fillthisbuffer. bufsize = {}", outputPortSettings.nBufferSize);
286 bufferWithOutputPort->cond.wait(ul, [bufferWithOutputPort] { return bufferWithOutputPort->done; });
289 log->debug(TAG, "receiveFromOutputPort signalled");
291 *data = static_cast<char*>(outputBufferMem); // caller takes ownership
292 *nFlags = outputBufferHeader->nFlags;
294 outputBufferMem = NULL;
296 // The slice height is all important - can't trust nFilledLen
298 log->debug(TAG, "receiveFromOutput:");
299 log->debug(TAG, " nSize = {}", outputBufferHeader->nSize);
300 log->debug(TAG, " nAllocLen = {}", outputBufferHeader->nAllocLen);
301 log->debug(TAG, " nFilledLen = {}", outputBufferHeader->nFilledLen);
302 log->debug(TAG, " nOffset = {}", outputBufferHeader->nOffset);
303 log->debug(TAG, " nInputPortIndex = {}", outputBufferHeader->nInputPortIndex);
304 log->debug(TAG, " nOutputPortIndex = {}", outputBufferHeader->nOutputPortIndex);
305 log->debug(TAG, " nFlags = {:#x}", outputBufferHeader->nFlags);
307 delete bufferWithOutputPort;
313 free(outputBufferMem);
314 outputBufferMem = NULL;
320 void OMX_Image_Decode::getImageInfo(int* width, int* height, int* stride, int* sliceHeight)
322 *width = outputPortSettings.format.image.nFrameWidth;
323 *height = outputPortSettings.format.image.nFrameHeight;
324 *stride = outputPortSettings.format.image.nStride;
325 *sliceHeight = outputPortSettings.format.image.nSliceHeight;
328 OMX_ERRORTYPE OMX_Image_Decode::cb_EmptyBufferDone(OMX_IN OMX_HANDLETYPE /*hcomp*/, OMX_IN OMX_PTR /*appdata*/, OMX_IN OMX_BUFFERHEADERTYPE* buffer)
330 log->debug(TAG, "CB: EmptyBufferDone");
331 log->debug(TAG, " nSize = {}", buffer->nSize);
332 log->debug(TAG, " nAllocLen = {}", buffer->nAllocLen);
333 log->debug(TAG, " nFilledLen = {}", buffer->nFilledLen);
334 log->debug(TAG, " nOffset = {}", buffer->nOffset);
335 log->debug(TAG, " nInputPortIndex = {}", buffer->nInputPortIndex);
336 log->debug(TAG, " nOutputPortIndex = {}", buffer->nOutputPortIndex);
337 log->debug(TAG, " nFlags = {:#x}", buffer->nFlags);
339 return OMX_ErrorNone;
342 OMX_ERRORTYPE OMX_Image_Decode::cb_FillBufferDone(OMX_IN OMX_HANDLETYPE hcomp, OMX_IN OMX_PTR appdata, OMX_IN OMX_BUFFERHEADERTYPE* buffer)
344 log->debug(TAG, "CB: FillBufferDone, handle: {}, appdata: {}, buffer: {}", static_cast<void*>(hcomp), static_cast<void*>(appdata), static_cast<void*>(buffer));
346 struct BufferWithOutputPort* bufferWithOutputPort = static_cast<struct BufferWithOutputPort*>(buffer->pAppPrivate);
347 bufferWithOutputPort->mutex.lock();
348 bufferWithOutputPort->done = true;
349 bufferWithOutputPort->mutex.unlock();
350 bufferWithOutputPort->cond.notify_one();
352 return OMX_ErrorNone;