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);
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;
135 error = OMX_GetParameter(componentHandle, OMX_IndexParamPortDefinition, &indTest);
136 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_GetParameter in OMX_Image_Decode::setSliceHeight()", error);
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);
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);
157 void OMX_Image_Decode::allocateInputBuffers(char* data)
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);
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);
171 void OMX_Image_Decode::allocateOutputBuffer()
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);
177 void OMX_Image_Decode::deallocateInputBuffers()
179 OMX_ERRORTYPE error = OMX_FreeBuffer(componentHandle, inputPort, inBuffer1);
181 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_FreeBuffer 1 in OMX_Image_Decode::deallocateInputBuffers()", error);
183 error = OMX_FreeBuffer(componentHandle, inputPort, inBuffer2);
185 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_FreeBuffer 2 in OMX_Image_Decode::deallocateInputBuffers()", error);
188 void OMX_Image_Decode::deallocateOutputBuffer()
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);
195 void OMX_Image_Decode::sendToInput()
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;
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");
210 void OMX_Image_Decode::waitForOutputPortSettingsChange()
212 eventsProcessorMutex.lock();
213 std::unique_lock<std::mutex> ul(eventWaitersMutex);
215 EventWaiter* eventWaiter = new EventWaiter();
216 eventWaiter->waiting = true;
217 eventWaiter->eventType = OMX_EventPortSettingsChanged;
218 eventWaiter->port = outputPort;
219 eventWaiters.push_back(eventWaiter);
221 eventsProcessorWake = true;
222 eventsProcessorMutex.unlock();
223 eventsProcessorCond.notify_one();
225 eventWaiter->cond.wait(ul); // sleep this thread
228 if (!eventWaiter->receivedEvent)
231 throw OMX_Exception("Error waiting for event in waitForOutputPortSettingsChange", 0);
234 // The event processor thread received an event and saved it here
235 // log->debug(TAG, "received outputportsettingschanged event!");
236 delete eventWaiter->receivedEvent;
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);
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);
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);
264 void OMX_Image_Decode::receiveFromOutput(char** data, int* nFlags)
266 void* outputBufferMem{};
270 outputBufferMem = malloc(outputPortSettings.nBufferSize);
271 memset(outputBufferMem, 0, outputPortSettings.nBufferSize);
272 outputBufferHeader->pBuffer = static_cast<OMX_U8*>(outputBufferMem);
274 struct BufferWithOutputPort* bufferWithOutputPort = new BufferWithOutputPort();
275 bufferWithOutputPort->bufhead = outputBufferHeader;
276 outputBufferHeader->pAppPrivate = static_cast<OMX_PTR>(bufferWithOutputPort);
278 std::unique_lock<std::mutex> ul(bufferWithOutputPort->mutex);
280 // log->debug(TAG, "calling fillthisbuffer. bufhead: {}, BufferWithOutput: {}", static_cast<void*>(outputBufferHeader), static_cast<void*>(bufferWithOutputPort));
284 error = OMX_FillThisBuffer(componentHandle, outputBufferHeader);
285 if (error != OMX_ErrorNone) throw OMX_Exception("OMX_FillThisBuffer in OMX_Image_Decode::receiveFromOutput()", error);
287 // log->debug(TAG, "called fillthisbuffer. bufsize = {}", outputPortSettings.nBufferSize);
289 bufferWithOutputPort->cond.wait(ul, [bufferWithOutputPort] { return bufferWithOutputPort->done; });
292 // log->debug(TAG, "receiveFromOutputPort signalled");
294 *data = static_cast<char*>(outputBufferMem); // caller takes ownership
295 *nFlags = outputBufferHeader->nFlags;
297 outputBufferMem = NULL;
299 // The slice height is all important - can't trust nFilledLen
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);
312 delete bufferWithOutputPort;
318 free(outputBufferMem);
319 outputBufferMem = NULL;
325 void OMX_Image_Decode::getImageInfo(int* width, int* height, int* stride, int* sliceHeight)
327 *width = outputPortSettings.format.image.nFrameWidth;
328 *height = outputPortSettings.format.image.nFrameHeight;
329 *stride = outputPortSettings.format.image.nStride;
330 *sliceHeight = outputPortSettings.format.image.nSliceHeight;
333 OMX_ERRORTYPE OMX_Image_Decode::cb_EmptyBufferDone(OMX_IN OMX_HANDLETYPE /*hcomp*/, OMX_IN OMX_PTR /*appdata*/, OMX_IN OMX_BUFFERHEADERTYPE* buffer)
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);
345 return OMX_ErrorNone;
348 OMX_ERRORTYPE OMX_Image_Decode::cb_FillBufferDone(OMX_IN OMX_HANDLETYPE hcomp, OMX_IN OMX_PTR appdata, OMX_IN OMX_BUFFERHEADERTYPE* buffer)
350 // log->debug(TAG, "CB: FillBufferDone, handle: {}, appdata: {}, buffer: {}", static_cast<void*>(hcomp), static_cast<void*>(appdata), static_cast<void*>(buffer));
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();
358 return OMX_ErrorNone;