Initial version of libomxil-vc4 for RPI3
[platform/adaptation/broadcom/libomxil-vc4.git] / interface / mmal / openmaxil / mmalomx_core.c
1 /*
2 Copyright (c) 2012, Broadcom Europe Ltd
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7     * Redistributions of source code must retain the above copyright
8       notice, this list of conditions and the following disclaimer.
9     * Redistributions in binary form must reproduce the above copyright
10       notice, this list of conditions and the following disclaimer in the
11       documentation and/or other materials provided with the distribution.
12     * Neither the name of the copyright holder nor the
13       names of its contributors may be used to endorse or promote products
14       derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "interface/vmcs_host/khronos/IL/OMX_Broadcom.h"
29 #include "mmalomx.h"
30 #include "mmalomx_commands.h"
31 #include "mmalomx_roles.h"
32 #include "mmalomx_registry.h"
33 #include "mmalomx_buffer.h"
34 #include "mmalomx_parameters.h"
35 #include "mmalomx_logging.h"
36
37 #include <util/mmal_util.h>
38 #include <util/mmal_util_params.h>
39 #include <string.h>
40 #include <stdio.h>
41
42 #define MAX_CMD_BUFFERS 5
43
44 #define PARAM_GET_PORT(port, component, index) \
45    if (index >= component->ports_num) return OMX_ErrorBadPortIndex; \
46    port = &component->ports[index]
47
48 static void *mmalomx_cmd_thread_func(void *arg);
49 #define MMALOMX_ZERO_COPY_THRESHOLD 256
50
51 /*****************************************************************************/
52 OMX_ERRORTYPE mmalomx_callback_event_handler(
53    MMALOMX_COMPONENT_T *component,
54    OMX_EVENTTYPE eEvent,
55    OMX_U32 nData1,
56    OMX_U32 nData2,
57    OMX_PTR pEventData)
58 {
59    LOG_DEBUG("component %p, eEvent %i, nData1 %u, nData2 %u, pEventData %p",
60              component, (int)eEvent, (unsigned int)nData1, (unsigned int)nData2, pEventData);
61    return component->callbacks.EventHandler((OMX_HANDLETYPE)&component->omx,
62          component->callbacks_data, eEvent, nData1, nData2, pEventData);
63 }
64
65 /*****************************************************************************/
66 static OMX_ERRORTYPE mmalomx_ComponentGetComponentVersion(
67    OMX_HANDLETYPE hComponent,
68    OMX_STRING pComponentName,
69    OMX_VERSIONTYPE* pComponentVersion,
70    OMX_VERSIONTYPE* pSpecVersion,
71    OMX_UUIDTYPE* pComponentUUID)
72 {
73    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
74    const char *short_name, *prefix;
75
76    LOG_TRACE("hComponent %p, componentName %p, componentVersion %p, "
77              "pSpecVersion %p, componentUUID %p",
78              hComponent, pComponentName, pComponentVersion, pSpecVersion,
79              pComponentUUID);
80
81    /* Sanity checks */
82    if (!hComponent)
83       return OMX_ErrorInvalidComponent;
84    if (component->state == OMX_StateInvalid)
85       return OMX_ErrorInvalidState;
86    if (!pComponentName || !pComponentVersion || !pSpecVersion || !pComponentUUID )
87       return OMX_ErrorBadParameter;
88
89    short_name = mmalomx_registry_component_name(component->registry_id, &prefix);
90
91    snprintf(pComponentName, OMX_MAX_STRINGNAME_SIZE, "%s%s", short_name, prefix);
92    pComponentVersion->nVersion = 0;
93    pSpecVersion->nVersion = OMX_VERSION;
94    snprintf((char *)(*pComponentUUID), sizeof(OMX_UUIDTYPE), "%s", pComponentName);
95
96    return OMX_ErrorNone;
97 }
98
99 /*****************************************************************************/
100 static OMX_ERRORTYPE mmalomx_ComponentSendCommand(
101    OMX_HANDLETYPE hComponent,
102    OMX_COMMANDTYPE Cmd,
103    OMX_U32 nParam1,
104    OMX_PTR pCmdData)
105 {
106    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
107    OMX_ERRORTYPE status = OMX_ErrorNone;
108
109    LOG_TRACE("hComponent %p, Cmd %i (%s), nParam1 %i (%s), pCmdData %p",
110              hComponent, Cmd, mmalomx_cmd_to_string(Cmd), (int)nParam1,
111              Cmd == OMX_CommandStateSet ? mmalomx_state_to_string((OMX_STATETYPE)nParam1) : "",
112              pCmdData);
113
114    /* Sanity checks */
115    if (!hComponent)
116       return OMX_ErrorInvalidComponent;
117    if (component->state == OMX_StateInvalid)
118       return OMX_ErrorInvalidState;
119
120    /* Sanity check port index */
121    if (Cmd == OMX_CommandFlush || Cmd == OMX_CommandMarkBuffer ||
122        Cmd == OMX_CommandPortEnable || Cmd == OMX_CommandPortDisable)
123    {
124       if (nParam1 != OMX_ALL && nParam1 >= component->ports_num)
125          return OMX_ErrorBadPortIndex;
126    }
127
128    if (Cmd == OMX_CommandStateSet ||
129        Cmd == OMX_CommandFlush ||
130        Cmd == OMX_CommandPortEnable ||
131        Cmd == OMX_CommandPortDisable)
132    {
133       status = mmalomx_command_queue(component, Cmd, nParam1);
134    }
135    else if (Cmd == OMX_CommandMarkBuffer)
136    {
137       status = mmalomx_command_port_mark(hComponent, nParam1, pCmdData);
138    }
139    else
140    {
141       status = OMX_ErrorNotImplemented;
142    }
143
144    return status;
145 }
146
147 /*****************************************************************************/
148 static MMAL_STATUS_T mmalomx_get_port_settings(MMALOMX_PORT_T *port, OMX_PARAM_PORTDEFINITIONTYPE *def)
149 {
150    MMAL_STATUS_T status = MMAL_SUCCESS;
151    MMAL_PORT_T *mmal = port->mmal;
152
153    def->eDomain = mmalil_es_type_to_omx_domain(mmal->format->type);
154    def->eDir = OMX_DirInput;
155    if (mmal->type == MMAL_PORT_TYPE_OUTPUT)
156       def->eDir = OMX_DirOutput;
157
158    if (def->eDomain == OMX_PortDomainVideo)
159    {
160       def->format.video.eColorFormat = OMX_COLOR_FormatUnused;
161       def->format.video.eCompressionFormat = mmalil_encoding_to_omx_video_coding(mmal->format->encoding);
162       if (def->format.video.eCompressionFormat == OMX_VIDEO_CodingUnused)
163          def->format.video.eColorFormat = mmalil_encoding_to_omx_color_format(mmal->format->encoding);
164
165       def->format.video.nBitrate = mmal->format->bitrate;
166       def->format.video.nFrameWidth = mmal->format->es->video.width;
167       if (mmal->format->es->video.crop.width)
168          def->format.video.nFrameWidth = mmal->format->es->video.crop.width;
169       def->format.video.nStride = mmal->format->es->video.width;
170       if (port->no_cropping)
171          def->format.video.nFrameWidth = def->format.video.nStride;
172       def->format.video.nStride =
173          mmal_encoding_width_to_stride(mmal->format->encoding, def->format.video.nStride);
174       def->format.video.nFrameHeight = mmal->format->es->video.height;
175       if (mmal->format->es->video.crop.height)
176          def->format.video.nFrameHeight = mmal->format->es->video.crop.height;
177       def->format.video.nSliceHeight = mmal->format->es->video.height;
178       if (port->no_cropping)
179          def->format.video.nFrameHeight = def->format.video.nSliceHeight;
180       if (mmal->format->es->video.frame_rate.den)
181          def->format.video.xFramerate = (((int64_t)mmal->format->es->video.frame_rate.num) << 16) /
182             mmal->format->es->video.frame_rate.den;
183       else
184          def->format.video.xFramerate = 0;
185    }
186    else if (def->eDomain == OMX_PortDomainImage)
187    {
188       def->format.image.eColorFormat = OMX_COLOR_FormatUnused;
189       def->format.image.eCompressionFormat = mmalil_encoding_to_omx_image_coding(mmal->format->encoding);
190       if (def->format.image.eCompressionFormat == OMX_IMAGE_CodingUnused)
191          def->format.image.eColorFormat = mmalil_encoding_to_omx_color_format(mmal->format->encoding);
192       if (mmal->format->encoding == MMAL_ENCODING_UNKNOWN)
193          def->format.image.eCompressionFormat = OMX_IMAGE_CodingAutoDetect;
194       def->format.image.nFrameWidth = mmal->format->es->video.width;
195       if (mmal->format->es->video.crop.width)
196          def->format.image.nFrameWidth = mmal->format->es->video.crop.width;
197       def->format.image.nStride = mmal->format->es->video.width;
198       if (port->no_cropping)
199          def->format.image.nFrameWidth = def->format.image.nStride;
200       def->format.image.nStride =
201          mmal_encoding_width_to_stride(mmal->format->encoding, def->format.image.nStride);
202       def->format.image.nFrameHeight = mmal->format->es->video.height;
203       if (mmal->format->es->video.crop.height)
204          def->format.image.nFrameHeight = mmal->format->es->video.crop.height;
205       def->format.image.nSliceHeight = mmal->format->es->video.height;
206       if (port->no_cropping)
207          def->format.image.nFrameHeight = def->format.image.nSliceHeight;
208    }
209    else if(def->eDomain == OMX_PortDomainAudio)
210    {
211       def->format.audio.eEncoding = mmalil_encoding_to_omx_audio_coding(mmal->format->encoding);
212    }
213    else
214    {
215       LOG_ERROR("%s: unsupported domain (%u)", mmal->name, def->eDomain);
216       status = MMAL_EINVAL;
217       goto finish;
218    }
219
220    def->nBufferAlignment = mmal->buffer_alignment_min;
221    def->nBufferCountActual = mmal->buffer_num;
222    def->nBufferCountMin = mmal->buffer_num_min;
223    def->nBufferSize = mmal->buffer_size;
224    if (def->nBufferSize < mmal->buffer_size_min)
225       def->nBufferSize = mmal->buffer_size_min;
226    def->bEnabled = port->enabled;
227    def->bPopulated = port->populated;
228
229  finish:
230    return status;
231 }
232
233 /*****************************************************************************/
234 static OMX_ERRORTYPE mmalomx_ComponentGetParameter(
235    OMX_HANDLETYPE hComponent,
236    OMX_INDEXTYPE nParamIndex,
237    OMX_PTR pParam)
238 {
239    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
240    MMALOMX_PORT_T *port = NULL;
241
242    LOG_TRACE("hComponent %p, nParamIndex 0x%x (%s), pParam %p",
243              hComponent, nParamIndex, mmalomx_param_to_string(nParamIndex), pParam);
244
245    /* Sanity checks */
246    if (!hComponent)
247       return OMX_ErrorInvalidComponent;
248    if (!pParam)
249       return OMX_ErrorBadParameter;
250    if (*(OMX_U32 *)pParam < sizeof(OMX_U32) + sizeof(OMX_VERSIONTYPE))
251       return OMX_ErrorBadParameter;
252    if (component->state == OMX_StateInvalid)
253       return OMX_ErrorInvalidState;
254
255    switch(nParamIndex)
256    {
257    case OMX_IndexParamAudioInit:
258    case OMX_IndexParamVideoInit:
259    case OMX_IndexParamImageInit:
260    case OMX_IndexParamOtherInit:
261       {
262          OMX_PORT_PARAM_TYPE *param = (OMX_PORT_PARAM_TYPE *)pParam;
263          param->nStartPortNumber = 0;
264          param->nPorts = component->ports_domain_num[OMX_PortDomainAudio];
265          if (nParamIndex == OMX_IndexParamAudioInit)
266             return OMX_ErrorNone;
267          param->nStartPortNumber += param->nPorts;
268          param->nPorts = component->ports_domain_num[OMX_PortDomainVideo];
269          if (nParamIndex == OMX_IndexParamVideoInit)
270             return OMX_ErrorNone;
271          param->nStartPortNumber += param->nPorts;
272          param->nPorts = component->ports_domain_num[OMX_PortDomainImage];
273          if (nParamIndex == OMX_IndexParamImageInit)
274             return OMX_ErrorNone;
275          param->nStartPortNumber += param->nPorts;
276          param->nPorts = component->ports_domain_num[OMX_PortDomainOther];
277       }
278       return OMX_ErrorNone;
279       break;
280    case OMX_IndexParamPortDefinition:
281       {
282          OMX_PARAM_PORTDEFINITIONTYPE *param = (OMX_PARAM_PORTDEFINITIONTYPE *)pParam;
283          PARAM_GET_PORT(port, component, param->nPortIndex);
284          return mmalil_error_to_omx(mmalomx_get_port_settings(port, param));
285       }
286       return OMX_ErrorNone;
287       break;
288    case OMX_IndexParamCompBufferSupplier:
289       {
290          OMX_PARAM_BUFFERSUPPLIERTYPE *param = (OMX_PARAM_BUFFERSUPPLIERTYPE *)pParam;
291          PARAM_GET_PORT(port, component, param->nPortIndex);
292          param->eBufferSupplier = OMX_BufferSupplyUnspecified;
293       }
294       return OMX_ErrorNone;
295       break;
296    case OMX_IndexParamPriorityMgmt:
297       {
298          OMX_PRIORITYMGMTTYPE *param = (OMX_PRIORITYMGMTTYPE *)pParam;
299          param->nGroupPriority = component->group_priority;
300          param->nGroupID = component->group_id;
301       }
302       return OMX_ErrorNone;
303       break;
304    case OMX_IndexParamVideoPortFormat:
305    case OMX_IndexParamAudioPortFormat:
306       {
307          OMX_VIDEO_PARAM_PORTFORMATTYPE *param = (OMX_VIDEO_PARAM_PORTFORMATTYPE *)pParam;
308          PARAM_GET_PORT(port, component, param->nPortIndex);
309
310          /* Populate our internal list of encodings the first time around */
311          if (!port->encodings_num)
312          {
313             port->encodings_header.id = MMAL_PARAMETER_SUPPORTED_ENCODINGS;
314             port->encodings_header.size = sizeof(port->encodings_header) + sizeof(port->encodings);
315             if (mmal_port_parameter_get(port->mmal, &port->encodings_header) == MMAL_SUCCESS)
316             {
317                 port->encodings_num = (port->encodings_header.size - sizeof(port->encodings_header)) /
318                    sizeof(port->encodings[0]);
319             }
320             if (!port->encodings_num)
321             {
322                port->encodings_num = 1;
323                port->encodings[0] = port->mmal->format->encoding;
324             }
325          }
326
327          if (param->nIndex >= port->encodings_num)
328             return OMX_ErrorNoMore;
329
330          if (nParamIndex == OMX_IndexParamVideoPortFormat)
331          {
332             param->eColorFormat = OMX_COLOR_FormatUnused;
333             param->eCompressionFormat =
334                mmalil_encoding_to_omx_video_coding(port->encodings[param->nIndex]);
335             if (param->eCompressionFormat == OMX_VIDEO_CodingUnused)
336                param->eColorFormat =
337                   mmalil_encoding_to_omx_color_format(port->encodings[param->nIndex]);
338             param->xFramerate = 0;
339          }
340          else
341          {
342             OMX_AUDIO_PARAM_PORTFORMATTYPE *aparam =
343                (OMX_AUDIO_PARAM_PORTFORMATTYPE *)pParam;
344             aparam->eEncoding =
345                mmalil_encoding_to_omx_audio_coding(port->encodings[param->nIndex]);
346          }
347          return OMX_ErrorNone;
348       }
349       break;
350    case OMX_IndexParamImagePortFormat:
351    case OMX_IndexParamOtherPortFormat:
352       break;
353    case OMX_IndexParamStandardComponentRole:
354       {
355          OMX_PARAM_COMPONENTROLETYPE *param = (OMX_PARAM_COMPONENTROLETYPE *)pParam;
356          const char *role = mmalomx_role_to_name(component->role);
357          if (!role)
358             role = component->name;
359          snprintf((char *)param->cRole, sizeof(param->cRole), "%s", role);
360       }
361       return OMX_ErrorNone;
362    default:
363       return mmalomx_parameter_get(component, nParamIndex, pParam);
364    }
365
366    return OMX_ErrorNotImplemented;
367 }
368
369 /*****************************************************************************/
370 static MMAL_STATUS_T mmalomx_set_port_settings(MMALOMX_PORT_T *mmalomx_port,
371    OMX_PARAM_PORTDEFINITIONTYPE *def)
372 {
373    MMAL_PORT_T *port = mmalomx_port->mmal;
374    uint32_t buffer_size_min = port->buffer_size_min;
375    MMAL_STATUS_T status;
376
377    port->format->type = mmalil_omx_domain_to_es_type(def->eDomain);
378    port->format->encoding_variant = 0;
379
380    if(def->eDomain == OMX_PortDomainVideo)
381    {
382       if (def->format.video.eCompressionFormat != OMX_VIDEO_CodingUnused)
383          port->format->encoding = mmalil_omx_video_coding_to_encoding(def->format.video.eCompressionFormat);
384       else
385          port->format->encoding = mmalil_omx_color_format_to_encoding(def->format.video.eColorFormat);
386
387       port->format->bitrate = def->format.video.nBitrate;
388       port->format->es->video.width = def->format.video.nFrameWidth;
389       if (!mmalomx_port->no_cropping)
390          port->format->es->video.crop.width = port->format->es->video.width;
391       if (mmal_encoding_stride_to_width(port->format->encoding, def->format.video.nStride))
392          port->format->es->video.width =
393             mmal_encoding_stride_to_width(port->format->encoding, def->format.video.nStride);
394       port->format->es->video.height = def->format.video.nFrameHeight;
395       if (!mmalomx_port->no_cropping)
396          port->format->es->video.crop.height = port->format->es->video.height;
397       if (def->format.video.nSliceHeight > def->format.video.nFrameHeight)
398          port->format->es->video.height = def->format.video.nSliceHeight;
399       port->format->es->video.frame_rate.num = def->format.video.xFramerate;
400       port->format->es->video.frame_rate.den = (1<<16);
401    }
402    else if(def->eDomain == OMX_PortDomainImage)
403    {
404       if (def->format.image.eCompressionFormat != OMX_IMAGE_CodingUnused)
405          port->format->encoding = mmalil_omx_image_coding_to_encoding(def->format.image.eCompressionFormat);
406       else
407          port->format->encoding = mmalil_omx_color_format_to_encoding(def->format.image.eColorFormat);
408
409       port->format->es->video.width = def->format.image.nFrameWidth;
410       if (!mmalomx_port->no_cropping)
411          port->format->es->video.crop.width = port->format->es->video.width;
412       if (mmal_encoding_stride_to_width(port->format->encoding, def->format.image.nStride))
413          port->format->es->video.width =
414             mmal_encoding_stride_to_width(port->format->encoding, def->format.image.nStride);
415       port->format->es->video.height = def->format.image.nFrameHeight;
416       if (!mmalomx_port->no_cropping)
417          port->format->es->video.crop.height = port->format->es->video.height;
418       if (def->format.image.nSliceHeight > def->format.image.nFrameHeight)
419          port->format->es->video.height = def->format.image.nSliceHeight;
420    }
421    else if(def->eDomain == OMX_PortDomainAudio)
422    {
423       port->format->encoding = mmalil_omx_audio_coding_to_encoding(def->format.audio.eEncoding);
424    }
425    else
426    {
427       port->format->encoding = MMAL_ENCODING_UNKNOWN;
428    }
429
430    port->buffer_num = def->nBufferCountActual;
431    port->buffer_size = def->nBufferSize;
432    if (port->buffer_size < port->buffer_size_min)
433       port->buffer_size = port->buffer_size_min;
434
435    status = mmal_port_format_commit(port);
436    if (status != MMAL_SUCCESS)
437       return status;
438
439    /* Acknowledge any ongoing port format changed event */
440    mmalomx_port->format_changed = MMAL_FALSE;
441
442    /* The minimum buffer size only changes when the format significantly changes
443     * and in that case we want to advertise the new requirement to the client. */
444    if (port->buffer_size_min != buffer_size_min)
445       port->buffer_size = port->buffer_size_min;
446
447    return MMAL_SUCCESS;
448 }
449
450 /*****************************************************************************/
451 static OMX_ERRORTYPE mmalomx_ComponentSetParameter(
452    OMX_HANDLETYPE hComponent,
453    OMX_INDEXTYPE nParamIndex,
454    OMX_PTR pParam)
455 {
456    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
457    MMALOMX_PORT_T *port = NULL;
458
459    LOG_TRACE("hComponent %p, nParamIndex 0x%x (%s), pParam %p",
460              hComponent, nParamIndex, mmalomx_param_to_string(nParamIndex), pParam);
461
462    /* Sanity checks */
463    if (!hComponent)
464       return OMX_ErrorInvalidComponent;
465    if (!pParam)
466       return OMX_ErrorBadParameter;
467    if (*(OMX_U32 *)pParam < sizeof(OMX_U32) + sizeof(OMX_VERSIONTYPE))
468       return OMX_ErrorBadParameter;
469    if (component->state == OMX_StateInvalid)
470       return OMX_ErrorInvalidState;
471
472    switch(nParamIndex)
473    {
474    case OMX_IndexParamPortDefinition:
475       {
476          OMX_PARAM_PORTDEFINITIONTYPE *param = (OMX_PARAM_PORTDEFINITIONTYPE *)pParam;
477          PARAM_GET_PORT(port, component, param->nPortIndex);
478          return mmalil_error_to_omx(mmalomx_set_port_settings(port, param));
479       }
480       return OMX_ErrorNone;
481       break;
482    case OMX_IndexParamCompBufferSupplier:
483       {
484          OMX_PARAM_BUFFERSUPPLIERTYPE *param = (OMX_PARAM_BUFFERSUPPLIERTYPE *)pParam;
485          PARAM_GET_PORT(port, component, param->nPortIndex);
486          //param->eBufferSupplier = OMX_BufferSupplyUnspecified;
487       }
488       return OMX_ErrorNone;
489       break;
490    case OMX_IndexParamPriorityMgmt:
491       {
492          OMX_PRIORITYMGMTTYPE *param = (OMX_PRIORITYMGMTTYPE *)pParam;
493
494          if (component->state != OMX_StateLoaded)
495          return OMX_ErrorIncorrectStateOperation;
496
497          component->group_priority = param->nGroupPriority;
498          component->group_id = param->nGroupID;
499       }
500       return OMX_ErrorNone;
501       break;
502    case OMX_IndexParamAudioPortFormat:
503       {
504          OMX_AUDIO_PARAM_PORTFORMATTYPE *param = (OMX_AUDIO_PARAM_PORTFORMATTYPE *)pParam;
505          PARAM_GET_PORT(port, component, param->nPortIndex);
506          port->mmal->format->encoding = mmalil_omx_audio_coding_to_encoding(param->eEncoding);
507          port->mmal->format->encoding_variant = 0;
508          if (mmal_port_format_commit(port->mmal) != MMAL_SUCCESS)
509             LOG_ERROR("OMX_IndexParamAudioPortFormat commit failed");
510          return OMX_ErrorNone;
511       }
512       break;
513    case OMX_IndexParamVideoPortFormat:
514       {
515          OMX_VIDEO_PARAM_PORTFORMATTYPE *param = (OMX_VIDEO_PARAM_PORTFORMATTYPE *)pParam;
516          PARAM_GET_PORT(port, component, param->nPortIndex);
517          if (param->eCompressionFormat != OMX_VIDEO_CodingUnused)
518             port->mmal->format->encoding = mmalil_omx_video_coding_to_encoding(param->eCompressionFormat);
519          else
520             port->mmal->format->encoding = mmalil_omx_color_format_to_encoding(param->eColorFormat);
521          port->mmal->format->encoding_variant = 0;
522
523          if (mmal_port_format_commit(port->mmal) != MMAL_SUCCESS)
524             LOG_ERROR("OMX_IndexParamAudioPortFormat commit failed");
525          return OMX_ErrorNone;
526       }
527       break;
528    case OMX_IndexParamImagePortFormat:
529    case OMX_IndexParamOtherPortFormat:
530       break;
531    case OMX_IndexParamStandardComponentRole:
532       {
533          OMX_PARAM_COMPONENTROLETYPE *param = (OMX_PARAM_COMPONENTROLETYPE *)pParam;
534          return mmalomx_role_set(component, (const char *)param->cRole);
535       }
536       break;
537    default:
538       {
539          OMX_ERRORTYPE status = mmalomx_parameter_set(component, nParamIndex, pParam);
540
541          /* Keep track of the zero-copy state */
542          if (status == OMX_ErrorNone && nParamIndex == OMX_IndexParamBrcmZeroCopy)
543          {
544             PARAM_GET_PORT(port, component, ((OMX_CONFIG_PORTBOOLEANTYPE *)pParam)->nPortIndex);
545             port->zero_copy = ((OMX_CONFIG_PORTBOOLEANTYPE *)pParam)->bEnabled;
546          }
547
548          return status;
549       }
550    }
551
552    return OMX_ErrorNotImplemented;
553 }
554
555 /*****************************************************************************/
556 static OMX_ERRORTYPE mmalomx_ComponentGetConfig(
557    OMX_HANDLETYPE hComponent,
558    OMX_INDEXTYPE nParamIndex,
559    OMX_PTR pParam)
560 {
561    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
562
563    LOG_TRACE("hComponent %p, nParamIndex 0x%x (%s), pParam %p",
564              hComponent, nParamIndex, mmalomx_param_to_string(nParamIndex), pParam);
565
566    /* Sanity checks */
567    if (!hComponent)
568       return OMX_ErrorInvalidComponent;
569    if (!pParam)
570       return OMX_ErrorBadParameter;
571    if (*(OMX_U32 *)pParam < sizeof(OMX_U32) + sizeof(OMX_VERSIONTYPE))
572       return OMX_ErrorBadParameter;
573    if (component->state == OMX_StateInvalid)
574       return OMX_ErrorInvalidState;
575
576    return mmalomx_parameter_get(component, nParamIndex, pParam);
577 }
578
579 /*****************************************************************************/
580 static OMX_ERRORTYPE mmalomx_ComponentSetConfig(
581    OMX_HANDLETYPE hComponent,
582    OMX_INDEXTYPE nParamIndex,
583    OMX_PTR pParam)
584 {
585    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
586
587    LOG_TRACE("hComponent %p, nParamIndex 0x%x (%s), pParam %p",
588              hComponent, nParamIndex, mmalomx_param_to_string(nParamIndex), pParam);
589
590    /* Sanity checks */
591    if (!hComponent)
592       return OMX_ErrorInvalidComponent;
593    if (!pParam)
594       return OMX_ErrorBadParameter;
595    if (*(OMX_U32 *)pParam < sizeof(OMX_U32) + sizeof(OMX_VERSIONTYPE))
596       return OMX_ErrorBadParameter;
597    if (component->state == OMX_StateInvalid)
598       return OMX_ErrorInvalidState;
599
600    return mmalomx_parameter_set(component, nParamIndex, pParam);
601 }
602
603 /*****************************************************************************/
604 static OMX_ERRORTYPE mmalomx_ComponentGetExtensionIndex(
605    OMX_HANDLETYPE hComponent,
606    OMX_STRING cParameterName,
607    OMX_INDEXTYPE* pIndexType)
608 {
609    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
610
611    LOG_TRACE("hComponent %p, cParameterName %s, pIndexType %p",
612              hComponent, cParameterName, pIndexType);
613
614    /* Sanity checks */
615    if (!hComponent)
616       return OMX_ErrorInvalidComponent;
617    if (component->state == OMX_StateInvalid)
618       return OMX_ErrorInvalidState;
619
620    return mmalomx_parameter_extension_index_get(cParameterName, pIndexType);
621 }
622
623 /*****************************************************************************/
624 static OMX_ERRORTYPE mmalomx_ComponentGetState(
625    OMX_HANDLETYPE hComponent,
626    OMX_STATETYPE* pState)
627 {
628    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
629    MMAL_PARAM_UNUSED(component);
630
631    LOG_TRACE("hComponent %p, pState, %p", hComponent, pState);
632
633    /* Sanity checks */
634    if (!hComponent)
635       return OMX_ErrorInvalidComponent;
636    if (!pState)
637       return OMX_ErrorBadParameter;
638
639    *pState = component->state;
640    return OMX_ErrorNone;
641 }
642
643 /*****************************************************************************/
644 static OMX_ERRORTYPE mmalomx_ComponentTunnelRequest(
645    OMX_HANDLETYPE hComponent,
646    OMX_U32 nPort,
647    OMX_HANDLETYPE hTunneledComp,
648    OMX_U32 nTunneledPort,
649    OMX_TUNNELSETUPTYPE* pTunnelSetup)
650 {
651    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
652    MMAL_PARAM_UNUSED(component);
653
654    LOG_TRACE("hComponent %p, nPort %i, hTunneledComp %p, nTunneledPort %i, "
655              "pTunnelSetup %p", hComponent, (int)nPort, hTunneledComp,
656              (int)nTunneledPort, pTunnelSetup);
657
658    /* Sanity checks */
659    if (!hComponent)
660       return OMX_ErrorInvalidComponent;
661    if (component->state == OMX_StateInvalid)
662       return OMX_ErrorInvalidState;
663    if (nPort >= component->ports_num)
664       return OMX_ErrorBadPortIndex;
665    if (component->state != OMX_StateLoaded && component->ports[nPort].enabled)
666       return OMX_ErrorIncorrectStateOperation;
667    if (hTunneledComp && !pTunnelSetup)
668       return OMX_ErrorBadParameter;
669
670    if (!hTunneledComp)
671       return OMX_ErrorNone;
672    return OMX_ErrorNotImplemented;
673 }
674
675 /*****************************************************************************/
676 static OMX_ERRORTYPE mmalomx_ComponentUseBuffer(
677    OMX_HANDLETYPE hComponent,
678    OMX_BUFFERHEADERTYPE** ppBuffer,
679    OMX_U32 nPortIndex,
680    OMX_PTR pAppPrivate,
681    OMX_U32 nSizeBytes,
682    OMX_U8* pBuffer)
683 {
684    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
685    OMX_ERRORTYPE status = OMX_ErrorNone;
686    MMAL_BOOL_T populated = MMAL_FALSE;
687    OMX_BUFFERHEADERTYPE *buffer;
688    MMALOMX_PORT_T *port;
689
690    LOG_TRACE("hComponent %p, ppBufferHdr %p, nPortIndex %i, pAppPrivate %p,"
691              " nSizeBytes %i, pBuffer %p", hComponent, ppBuffer,
692              (int)nPortIndex, pAppPrivate, (int)nSizeBytes, pBuffer);
693
694    /* Sanity checks */
695    if (!hComponent)
696       return OMX_ErrorInvalidComponent;
697    if (!ppBuffer)
698       return OMX_ErrorBadParameter;
699    if (component->state == OMX_StateInvalid)
700       return OMX_ErrorInvalidState;
701    if (nPortIndex >= component->ports_num)
702       return OMX_ErrorBadPortIndex;
703
704    /* Make sure any previous command has been processed.
705    * This is not ideal since done inline but in practice the actual
706    * notification to the client will not be done as part of this call. */
707    mmalomx_commands_actions_check(component);
708
709    port = &component->ports[nPortIndex];
710    MMALOMX_LOCK_PORT(component, port);
711
712    if (!(port->actions & MMALOMX_ACTION_CHECK_ALLOCATED))
713       status = OMX_ErrorIncorrectStateOperation;
714    if (port->populated)
715       status = OMX_ErrorIncorrectStateOperation;
716    if (status != OMX_ErrorNone)
717       goto error;
718
719    /* Check for mismatched calls to UseBuffer/AllocateBuffer */
720    if (port->buffers && port->buffers_allocated)
721    {
722       status = OMX_ErrorBadParameter;
723       goto error;
724    }
725
726    /* Sanity check buffer size */
727    if (nSizeBytes < port->mmal->buffer_size_min)
728    {
729       LOG_ERROR("buffer size too small (%i/%i)", (int)nSizeBytes,
730                 (int)port->mmal->buffer_size_min);
731       status = OMX_ErrorBadParameter;
732       goto error;
733    }
734    if (!port->buffers)
735       port->mmal->buffer_size = nSizeBytes;
736    if (nSizeBytes > port->mmal->buffer_size)
737    {
738       LOG_ERROR("buffer size too big (%i/%i)", (int)nSizeBytes,
739                 (int)port->mmal->buffer_size);
740       status = OMX_ErrorBadParameter;
741       goto error;
742    }
743
744    buffer = calloc( 1, sizeof(*buffer) );
745    if (!buffer)
746    {
747       status = OMX_ErrorInsufficientResources;
748       goto error;
749    }
750
751    buffer->nSize = sizeof(*buffer);
752    buffer->nVersion.nVersion = OMX_VERSION;
753    buffer->nAllocLen = nSizeBytes;
754    buffer->pBuffer = pBuffer;
755    buffer->pAppPrivate = pAppPrivate;
756    if (port->direction == OMX_DirInput)
757    {
758       buffer->nInputPortIndex = nPortIndex;
759       buffer->pOutputPortPrivate = pAppPrivate;
760    }
761    else
762    {
763       buffer->nOutputPortIndex = nPortIndex;
764       buffer->pInputPortPrivate = pAppPrivate;
765    }
766
767    *ppBuffer = buffer;
768    port->buffers++;
769    port->buffers_allocated = MMAL_FALSE;
770    port->populated = populated = port->buffers == port->mmal->buffer_num;
771
772    MMALOMX_UNLOCK_PORT(component, port);
773
774    LOG_DEBUG("allocated %i/%i buffers", port->buffers, port->mmal->buffer_num);
775
776    if (populated)
777       mmalomx_commands_actions_signal(component);
778
779    return OMX_ErrorNone;
780
781 error:
782    MMALOMX_UNLOCK_PORT(component, port);
783    return status;
784 }
785
786 /*****************************************************************************/
787 static OMX_ERRORTYPE mmalomx_ComponentAllocateBuffer(
788    OMX_HANDLETYPE hComponent,
789    OMX_BUFFERHEADERTYPE** ppBuffer,
790    OMX_U32 nPortIndex,
791    OMX_PTR pAppPrivate,
792    OMX_U32 nSizeBytes)
793 {
794    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
795    OMX_ERRORTYPE status = OMX_ErrorNone;
796    MMAL_BOOL_T populated = MMAL_FALSE;
797    OMX_BUFFERHEADERTYPE *buffer = 0;
798    MMALOMX_PORT_T *port;
799
800    LOG_TRACE("hComponent %p, ppBuffer %p, nPortIndex %i, pAppPrivate %p, "
801              "nSizeBytes %i", hComponent, ppBuffer, (int)nPortIndex,
802              pAppPrivate, (int)nSizeBytes);
803
804    /* Sanity checks */
805    if (!hComponent)
806       return OMX_ErrorInvalidComponent;
807    if (!ppBuffer)
808       return OMX_ErrorBadParameter;
809    if (component->state == OMX_StateInvalid)
810       return OMX_ErrorInvalidState;
811    if (nPortIndex >= component->ports_num)
812       return OMX_ErrorBadPortIndex;
813
814    /* Make sure any previous command has been processed.
815    * This is not ideal since done inline but in practice the actual
816    * notification to the client will not be done as part of this call. */
817    mmalomx_commands_actions_check(component);
818
819    port = &component->ports[nPortIndex];
820    MMALOMX_LOCK_PORT(component, port);
821
822    if (!(port->actions & MMALOMX_ACTION_CHECK_ALLOCATED))
823       status = OMX_ErrorIncorrectStateOperation;
824    if (port->populated)
825       status = OMX_ErrorIncorrectStateOperation;
826    if (status != OMX_ErrorNone)
827       goto error;
828
829    /* Check for mismatched calls to UseBuffer/AllocateBuffer */
830    if (!status && port->buffers && !port->buffers_allocated)
831    {
832       status = OMX_ErrorBadParameter;
833       goto error;
834    }
835
836    /* Sanity check buffer size */
837    if (nSizeBytes < port->mmal->buffer_size_min)
838    {
839       LOG_ERROR("buffer size too small (%i/%i)", (int)nSizeBytes,
840                 (int)port->mmal->buffer_size_min);
841       status = OMX_ErrorBadParameter;
842       goto error;
843    }
844    if (!port->buffers)
845       port->mmal->buffer_size = nSizeBytes;
846    if (nSizeBytes > port->mmal->buffer_size)
847    {
848       LOG_ERROR("buffer size too big (%i/%i)", (int)nSizeBytes,
849                 (int)port->mmal->buffer_size);
850       status = OMX_ErrorBadParameter;
851       goto error;
852    }
853
854    /* Set the zero-copy mode */
855    if (!port->buffers_allocated && nSizeBytes > MMALOMX_ZERO_COPY_THRESHOLD &&
856        !port->zero_copy)
857    {
858       MMAL_STATUS_T status = mmal_port_parameter_set_boolean(port->mmal,
859          MMAL_PARAMETER_ZERO_COPY, MMAL_TRUE);
860       if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
861          LOG_ERROR("failed to enable zero copy on %s", port->mmal->name);
862    }
863
864    buffer = calloc( 1, sizeof(*buffer) );
865    if (!buffer)
866    {
867       status = OMX_ErrorInsufficientResources;
868       goto error;
869    }
870
871    buffer->pBuffer = mmal_port_payload_alloc(port->mmal, nSizeBytes);
872    if (!buffer->pBuffer)
873    {
874       status = OMX_ErrorInsufficientResources;
875       goto error;
876    }
877
878    buffer->nSize = sizeof(*buffer);
879    buffer->nVersion.nVersion = OMX_VERSION;
880    buffer->nAllocLen = nSizeBytes;
881    buffer->pAppPrivate = pAppPrivate;
882    if (port->direction == OMX_DirInput)
883    {
884       buffer->nInputPortIndex = nPortIndex;
885       buffer->pOutputPortPrivate = pAppPrivate;
886    }
887    else
888    {
889       buffer->nOutputPortIndex = nPortIndex;
890       buffer->pInputPortPrivate = pAppPrivate;
891    }
892    /* Keep an unmodified copy of the pointer for when we come to free it */
893    buffer->pPlatformPrivate = (OMX_PTR)buffer->pBuffer;
894
895    *ppBuffer = buffer;
896    port->buffers++;
897    port->buffers_allocated = MMAL_TRUE;
898    port->populated = populated = port->buffers == port->mmal->buffer_num;
899
900    MMALOMX_UNLOCK_PORT(component, port);
901
902    LOG_DEBUG("allocated %i/%i buffers", port->buffers, port->mmal->buffer_num);
903
904    if (populated)
905       mmalomx_commands_actions_signal(component);
906
907    return OMX_ErrorNone;
908
909 error:
910    if (!port->buffers_allocated && !port->zero_copy)
911       mmal_port_parameter_set_boolean(port->mmal, MMAL_PARAMETER_ZERO_COPY, MMAL_FALSE);
912
913    MMALOMX_UNLOCK_PORT(component, port);
914    LOG_ERROR("failed to allocate %i/%i buffers", port->buffers, port->mmal->buffer_num);
915    if (buffer)
916       free(buffer);
917    return status;
918 }
919
920 /*****************************************************************************/
921 static OMX_ERRORTYPE mmalomx_ComponentFreeBuffer(
922    OMX_HANDLETYPE hComponent,
923    OMX_U32 nPortIndex,
924    OMX_BUFFERHEADERTYPE* pBuffer)
925 {
926    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
927    OMX_ERRORTYPE status = OMX_ErrorNone;
928    MMAL_BOOL_T unpopulated, allocated;
929    MMALOMX_PORT_T *port;
930    unsigned int buffers;
931
932    LOG_TRACE("hComponent %p, nPortIndex %i, pBuffer %p",
933              hComponent, (int)nPortIndex, pBuffer);
934
935    /* Sanity checks */
936    if (!hComponent)
937       return OMX_ErrorInvalidComponent;
938    if (!pBuffer)
939       return OMX_ErrorBadParameter;
940    if (nPortIndex >= component->ports_num)
941       return OMX_ErrorBadPortIndex;
942
943    /* Make sure any previous command has been processed.
944    * This is not ideal since done inline but in practice the actual
945    * notification to the client will not be done as part of this call. */
946    mmalomx_commands_actions_check(component);
947
948    port = &component->ports[nPortIndex];
949    MMALOMX_LOCK_PORT(component, port);
950
951    if (!port->buffers)
952    {
953       status = OMX_ErrorBadParameter;
954       goto error;
955    }
956
957    buffers = --port->buffers;
958    port->populated = MMAL_FALSE;
959    unpopulated = !(port->actions & MMALOMX_ACTION_CHECK_DEALLOCATED);
960    allocated = port->buffers_allocated;
961
962    MMALOMX_UNLOCK_PORT(component, port);
963
964    if (allocated) /* Free the unmodified pointer */
965       mmal_port_payload_free(port->mmal, pBuffer->pPlatformPrivate);
966    free(pBuffer);
967
968    if (allocated && !port->zero_copy) /* Reset the zero-copy status */
969       mmal_port_parameter_set_boolean(port->mmal, MMAL_PARAMETER_ZERO_COPY, MMAL_FALSE);
970
971    LOG_DEBUG("freed %i/%i buffers", port->mmal->buffer_num - port->buffers, port->mmal->buffer_num);
972
973    if (unpopulated)
974       mmalomx_callback_event_handler(component, OMX_EventError, OMX_ErrorPortUnpopulated, 0, NULL);
975
976    if (!buffers)
977       mmalomx_commands_actions_signal(component);
978
979    return OMX_ErrorNone;
980
981 error:
982    MMALOMX_UNLOCK_PORT(component, port);
983    return status;
984 }
985
986 /*****************************************************************************/
987 static OMX_ERRORTYPE mmalomx_ComponentEmptyThisBuffer(
988    OMX_HANDLETYPE hComponent,
989    OMX_BUFFERHEADERTYPE* pBuffer)
990 {
991    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
992
993    if (ENABLE_MMAL_EXTRA_LOGGING)
994       LOG_TRACE("hComponent %p, port %i, pBuffer %p", hComponent,
995                 pBuffer ? (int)pBuffer->nInputPortIndex : -1, pBuffer);
996
997    return mmalomx_buffer_send(component, pBuffer, OMX_DirInput);
998 }
999
1000 /*****************************************************************************/
1001 static OMX_ERRORTYPE mmalomx_ComponentFillThisBuffer(
1002    OMX_HANDLETYPE hComponent,
1003    OMX_BUFFERHEADERTYPE* pBuffer)
1004 {
1005    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
1006
1007    if (ENABLE_MMAL_EXTRA_LOGGING)
1008       LOG_TRACE("hComponent %p, port %i, pBuffer %p", hComponent,
1009                 pBuffer ? (int)pBuffer->nOutputPortIndex : -1, pBuffer);
1010
1011   return mmalomx_buffer_send(component, pBuffer, OMX_DirOutput);
1012 }
1013
1014 /*****************************************************************************/
1015 static OMX_ERRORTYPE mmalomx_ComponentSetCallbacks(
1016    OMX_HANDLETYPE hComponent,
1017    OMX_CALLBACKTYPE* pCallbacks,
1018    OMX_PTR pAppData)
1019 {
1020    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
1021    MMAL_PARAM_UNUSED(component);
1022
1023    LOG_TRACE("hComponent %p, pCallbacks %p, pAppData %p",
1024               hComponent, pCallbacks, pAppData);
1025
1026    /* Sanity checks */
1027    if (!hComponent)
1028       return OMX_ErrorInvalidComponent;
1029    if (!pCallbacks)
1030       return OMX_ErrorBadParameter;
1031    if (component->state == OMX_StateInvalid)
1032       return OMX_ErrorInvalidState;
1033
1034    if (component->state != OMX_StateLoaded)
1035       return OMX_ErrorInvalidState;
1036
1037    component->callbacks = *pCallbacks;
1038    component->callbacks_data = pAppData;
1039    return OMX_ErrorNone;
1040 }
1041
1042 /*****************************************************************************/
1043 static OMX_ERRORTYPE mmalomx_ComponentDeInit(
1044   OMX_HANDLETYPE hComponent)
1045 {
1046    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
1047    MMAL_PARAM_UNUSED(component);
1048
1049    LOG_TRACE("hComponent %p", hComponent);
1050
1051    /* Sanity checks */
1052    if (!hComponent)
1053       return OMX_ErrorInvalidComponent;
1054
1055    return OMX_ErrorNone;
1056 }
1057
1058 /*****************************************************************************/
1059 static OMX_ERRORTYPE mmalomx_ComponentUseEGLImage(
1060    OMX_HANDLETYPE hComponent,
1061    OMX_BUFFERHEADERTYPE** ppBufferHdr,
1062    OMX_U32 nPortIndex,
1063    OMX_PTR pAppPrivate,
1064    void* eglImage)
1065 {
1066    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
1067    MMAL_PARAM_UNUSED(component);
1068
1069    LOG_TRACE("hComponent %p, ppBufferHdr %p, nPortIndex %i, pAppPrivate %p,"
1070              " eglImage %p", hComponent, ppBufferHdr, (int)nPortIndex,
1071              pAppPrivate, eglImage);
1072
1073    /* Sanity checks */
1074    if (!hComponent)
1075       return OMX_ErrorInvalidComponent;
1076    if (component->state == OMX_StateInvalid)
1077       return OMX_ErrorInvalidState;
1078
1079    return OMX_ErrorNotImplemented;
1080 }
1081
1082 /*****************************************************************************/
1083 static OMX_ERRORTYPE mmalomx_ComponentRoleEnum(
1084    OMX_HANDLETYPE hComponent,
1085    OMX_U8 *cRole,
1086    OMX_U32 nIndex)
1087 {
1088    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
1089    MMALOMX_ROLE_T role;
1090
1091    LOG_TRACE("hComponent %p, cRole %p, nIndex %i",
1092              hComponent, cRole, (int)nIndex);
1093
1094    /* Sanity checks */
1095    if (!hComponent)
1096       return OMX_ErrorInvalidComponent;
1097    if (component->state == OMX_StateInvalid)
1098       return OMX_ErrorInvalidState;
1099
1100    role = mmalomx_registry_component_roles(component->registry_id, nIndex);
1101    if (!role)
1102       return OMX_ErrorNoMore;
1103    if (!mmalomx_role_to_name(role))
1104       return OMX_ErrorNoMore;
1105
1106    strcpy((char *)cRole, mmalomx_role_to_name(role));
1107    return OMX_ErrorNone;
1108 }
1109
1110 /*****************************************************************************/
1111 OMX_API OMX_ERRORTYPE OMX_APIENTRY MMALOMX_EXPORT(OMX_Init)(void)
1112 {
1113    mmalomx_logging_init();
1114    LOG_TRACE("Init");
1115    return OMX_ErrorNone;
1116 }
1117
1118 /*****************************************************************************/
1119 OMX_API OMX_ERRORTYPE OMX_APIENTRY MMALOMX_EXPORT(OMX_Deinit)(void)
1120 {
1121    LOG_TRACE("Deinit");
1122    mmalomx_logging_deinit();
1123    return OMX_ErrorNone;
1124 }
1125
1126 /*****************************************************************************/
1127 OMX_API OMX_ERRORTYPE OMX_APIENTRY MMALOMX_EXPORT(OMX_ComponentNameEnum)(
1128    OMX_STRING cComponentName,
1129    OMX_U32 nNameLength,
1130    OMX_U32 nIndex)
1131 {
1132    const char *prefix, *name;
1133    name = mmalomx_registry_component_name(nIndex, &prefix);
1134
1135    LOG_TRACE("cComponentName %p, nNameLength %i, nIndex %i",
1136              cComponentName, (int)nNameLength, (int)nIndex);
1137
1138    /* Sanity checking */
1139    if (!cComponentName)
1140       return OMX_ErrorBadParameter;
1141    if (!name)
1142       return OMX_ErrorNoMore;
1143    if (nNameLength <= strlen(name) + strlen(prefix))
1144       return OMX_ErrorBadParameter;
1145
1146    sprintf(cComponentName, "%s%s", prefix, name);
1147    LOG_TRACE("cComponentName: %s", cComponentName);
1148    return OMX_ErrorNone;
1149 }
1150
1151 /*****************************************************************************/
1152 static void mmalomx_buffer_cb_control(
1153    MMAL_PORT_T *port,
1154    MMAL_BUFFER_HEADER_T *buffer)
1155 {
1156    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)port->userdata;
1157
1158    LOG_DEBUG("received event %4.4s on port %s", (char *)&buffer->cmd, port->name);
1159
1160    if (buffer->cmd == MMAL_EVENT_ERROR)
1161    {
1162       mmalomx_callback_event_handler(component, OMX_EventError,
1163          mmalil_error_to_omx(*(MMAL_STATUS_T *)buffer->data), 0, NULL);
1164    }
1165    else if (buffer->cmd == MMAL_EVENT_EOS &&
1166             buffer->length == sizeof(MMAL_EVENT_END_OF_STREAM_T))
1167    {
1168       MMAL_EVENT_END_OF_STREAM_T *eos = (MMAL_EVENT_END_OF_STREAM_T *)buffer->data;
1169       if (eos->port_index < port->component->input_num)
1170       {
1171          MMALOMX_PORT_T *omx_port = (MMALOMX_PORT_T *)
1172             port->component->input[eos->port_index]->userdata;
1173          LOG_DEBUG("send EOS on %i", omx_port->index);
1174          mmalomx_callback_event_handler(component, OMX_EventBufferFlag,
1175             omx_port->index, OMX_BUFFERFLAG_EOS, NULL);
1176       }
1177    }
1178
1179    mmal_buffer_header_release(buffer);
1180 }
1181
1182 /*****************************************************************************/
1183 OMX_API OMX_ERRORTYPE OMX_APIENTRY MMALOMX_EXPORT(OMX_GetHandle)(
1184    OMX_HANDLETYPE* pHandle,
1185    OMX_STRING cComponentName,
1186    OMX_PTR pAppData,
1187    OMX_CALLBACKTYPE* pCallBacks)
1188 {
1189    OMX_ERRORTYPE status = OMX_ErrorInsufficientResources;
1190    MMALOMX_COMPONENT_T *component = 0;
1191    MMAL_COMPONENT_T *mmal_component = 0;
1192    MMAL_STATUS_T mmal_status;
1193    unsigned int i, ports_num;
1194    OMX_PORTDOMAINTYPE domain;
1195    const char *mmal_name;
1196    int registry_id;
1197
1198    LOG_TRACE("pHandle %p, cComponentName %s, pAppData %p, pCallBacks %p",
1199              pHandle, cComponentName, pAppData, pCallBacks);
1200
1201    /* Sanity check params */
1202    if (!pHandle || !cComponentName || !pCallBacks)
1203       return OMX_ErrorBadParameter;
1204
1205    /* Find component */
1206    registry_id = mmalomx_registry_find_component(cComponentName);
1207    if (registry_id < 0)
1208       return OMX_ErrorComponentNotFound;
1209
1210    /* create and setup component */
1211    mmal_name = mmalomx_registry_component_mmal(registry_id);
1212    mmal_status = mmal_component_create(mmal_name, &mmal_component);
1213    if (mmal_status != MMAL_SUCCESS)
1214    {
1215       LOG_ERROR("could not create mmal component %s", mmal_name);
1216       return mmalil_error_to_omx(mmal_status);
1217    }
1218    mmal_status = mmal_port_enable(mmal_component->control, mmalomx_buffer_cb_control);
1219    if (mmal_status != MMAL_SUCCESS)
1220    {
1221       LOG_ERROR("could not enable %s", mmal_component->control->name);
1222       mmal_component_destroy(mmal_component);
1223       return mmalil_error_to_omx(mmal_status);
1224    }
1225
1226    ports_num = mmal_component->port_num - 1;
1227
1228    component = calloc(1, sizeof(*component) + ports_num * sizeof(*component->ports));
1229    if (!component)
1230    {
1231       mmal_component_destroy(mmal_component);
1232       return OMX_ErrorInsufficientResources;
1233    }
1234
1235    if (vcos_mutex_create(&component->lock, "mmalomx lock") != VCOS_SUCCESS)
1236    {
1237       mmal_component_destroy(mmal_component);
1238       free(component);
1239       return OMX_ErrorInsufficientResources;
1240    }
1241    if (vcos_mutex_create(&component->lock_port, "mmalomx port lock") != VCOS_SUCCESS)
1242    {
1243       vcos_mutex_delete(&component->lock);
1244       mmal_component_destroy(mmal_component);
1245       free(component);
1246       return OMX_ErrorInsufficientResources;
1247    }
1248
1249    component->omx.nSize = sizeof(component->omx);
1250    component->omx.nVersion.nVersion = OMX_VERSION;
1251    component->mmal = mmal_component;
1252    component->state = OMX_StateLoaded;
1253    component->callbacks = *pCallBacks;
1254    component->callbacks_data = pAppData;
1255    component->ports = (MMALOMX_PORT_T *)&component[1];
1256    component->registry_id = registry_id;
1257    component->name = mmalomx_registry_component_name(registry_id, 0);
1258    component->role = mmalomx_registry_component_roles(registry_id, 0);
1259
1260    // FIXME: make this configurable
1261    component->cmd_thread_used = MMAL_TRUE;
1262
1263    /* Sort the ports into separate OMX domains */
1264    for (domain = OMX_PortDomainAudio; domain < OMX_PortDomainOther; domain++)
1265    {
1266       for (i = 1; i < mmal_component->port_num; i++)
1267       {
1268          if (domain == mmalil_es_type_to_omx_domain(mmal_component->port[i]->format->type))
1269          {
1270             component->ports[component->ports_num].mmal = mmal_component->port[i];
1271             component->ports_domain_num[domain]++;
1272             component->ports_num++;
1273          }
1274       }
1275    }
1276    LOG_DEBUG("ports: %i audio, %i video",
1277       component->ports_domain_num[OMX_PortDomainAudio],
1278       component->ports_domain_num[OMX_PortDomainVideo]);
1279
1280    /* Setup our ports */
1281    for (i = 0; i < component->ports_num; i++)
1282    {
1283       component->ports[i].component = component;
1284       if (component->ports[i].mmal->type == MMAL_PORT_TYPE_OUTPUT)
1285          component->ports[i].direction = OMX_DirOutput;
1286       component->ports[i].index = i;
1287       component->ports[i].enabled = MMAL_TRUE;
1288       component->ports[i].pool =
1289          mmal_port_pool_create(component->ports[i].mmal, 0, 0);
1290       if (!component->ports[i].pool)
1291          goto error;
1292       component->ports[i].mmal->userdata = (struct MMAL_PORT_USERDATA_T *)&component->ports[i];
1293    }
1294    mmal_component->control->userdata = (struct MMAL_PORT_USERDATA_T *)component;
1295
1296    /* Create our OMX commands queue */
1297    component->cmd_queue = mmal_queue_create();
1298    if (!component->cmd_queue)
1299       goto error;
1300    component->cmd_pool = mmal_pool_create(MAX_CMD_BUFFERS, 0);
1301    if (!component->cmd_pool)
1302       goto error;
1303
1304    if (component->cmd_thread_used &&
1305        vcos_semaphore_create(&component->cmd_sema,
1306                              "mmalomx sema", 0) != VCOS_SUCCESS)
1307    {
1308       component->cmd_thread_used = MMAL_FALSE;
1309       goto error;
1310    }
1311
1312    if (component->cmd_thread_used &&
1313        vcos_thread_create(&component->cmd_thread, component->name, NULL,
1314                           mmalomx_cmd_thread_func, component) != VCOS_SUCCESS)
1315    {
1316       vcos_semaphore_delete(&component->cmd_sema);
1317       component->cmd_thread_used = MMAL_FALSE;
1318       goto error;
1319    }
1320
1321    /* Set the function pointer for the component's interface */
1322    component->omx.GetComponentVersion = mmalomx_ComponentGetComponentVersion;
1323    component->omx.SendCommand = mmalomx_ComponentSendCommand;
1324    component->omx.GetParameter = mmalomx_ComponentGetParameter;
1325    component->omx.SetParameter = mmalomx_ComponentSetParameter;
1326    component->omx.GetConfig = mmalomx_ComponentGetConfig;
1327    component->omx.SetConfig = mmalomx_ComponentSetConfig;
1328    component->omx.GetExtensionIndex = mmalomx_ComponentGetExtensionIndex;
1329    component->omx.GetState = mmalomx_ComponentGetState;
1330    component->omx.ComponentTunnelRequest = mmalomx_ComponentTunnelRequest;
1331    component->omx.UseBuffer = mmalomx_ComponentUseBuffer;
1332    component->omx.AllocateBuffer = mmalomx_ComponentAllocateBuffer;
1333    component->omx.FreeBuffer = mmalomx_ComponentFreeBuffer;
1334    component->omx.EmptyThisBuffer = mmalomx_ComponentEmptyThisBuffer;
1335    component->omx.FillThisBuffer = mmalomx_ComponentFillThisBuffer;
1336    component->omx.SetCallbacks = mmalomx_ComponentSetCallbacks;
1337    component->omx.ComponentDeInit = mmalomx_ComponentDeInit;
1338    component->omx.UseEGLImage = mmalomx_ComponentUseEGLImage;
1339    component->omx.ComponentRoleEnum = mmalomx_ComponentRoleEnum;
1340    *pHandle = (OMX_HANDLETYPE)&component->omx;
1341
1342    return OMX_ErrorNone;
1343
1344  error:
1345    MMALOMX_IMPORT(OMX_FreeHandle)((OMX_HANDLETYPE)&component->omx);
1346    return status;
1347 }
1348
1349 /*****************************************************************************/
1350 OMX_API OMX_ERRORTYPE OMX_APIENTRY MMALOMX_EXPORT(OMX_FreeHandle)(
1351    OMX_HANDLETYPE hComponent)
1352 {
1353    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
1354    OMX_ERRORTYPE status;
1355    unsigned int i;
1356
1357    LOG_TRACE("hComponent %p", hComponent);
1358
1359    /* Sanity check */
1360    if (!hComponent)
1361       return OMX_ErrorInvalidComponent;
1362
1363    if (component->omx.ComponentDeInit)
1364    {
1365       status = component->omx.ComponentDeInit(hComponent);
1366       if (status != OMX_ErrorNone)
1367       {
1368          LOG_ERROR("ComponentDeInit failed");
1369          return status;
1370       }
1371    }
1372
1373    if (component->cmd_thread_used)
1374    {
1375       component->cmd_thread_used = MMAL_FALSE;
1376       vcos_semaphore_post(&component->cmd_sema);
1377       vcos_thread_join(&component->cmd_thread, NULL);
1378    }
1379
1380    mmal_component_destroy(component->mmal);
1381    for (i = 0; i < component->ports_num; i++)
1382       if (component->ports[i].pool)
1383          mmal_pool_destroy(component->ports[i].pool);
1384
1385    if (component->cmd_pool)
1386       mmal_pool_destroy(component->cmd_pool);
1387    if (component->cmd_queue)
1388       mmal_queue_destroy(component->cmd_queue);
1389    if (component->cmd_thread_used)
1390       vcos_semaphore_delete(&component->cmd_sema);
1391    vcos_mutex_delete(&component->lock_port);
1392    vcos_mutex_delete(&component->lock);
1393    free(component);
1394    return OMX_ErrorNone;
1395 }
1396
1397 /*****************************************************************************/
1398 OMX_API OMX_ERRORTYPE MMALOMX_EXPORT(OMX_GetRolesOfComponent)(
1399    OMX_STRING compName,
1400    OMX_U32 *pNumRoles,
1401    OMX_U8 **roles)
1402 {
1403    OMX_U32 i, num_roles;
1404    MMALOMX_ROLE_T role;
1405    int registry_id;
1406
1407    LOG_TRACE("compName %s, pNumRoles %p, roles %p", compName, pNumRoles, roles);
1408
1409    /* Sanity checks */
1410    if (!compName || !pNumRoles)
1411       return OMX_ErrorBadParameter;
1412
1413    if (!roles || *pNumRoles > MMALOMX_MAX_ROLES)
1414       num_roles = MMALOMX_MAX_ROLES;
1415    else
1416       num_roles = *pNumRoles;
1417    *pNumRoles = 0;
1418
1419    /* Find component */
1420    registry_id = mmalomx_registry_find_component(compName);
1421    if (registry_id < 0)
1422       return OMX_ErrorComponentNotFound;
1423
1424    /* Enumerate Roles */
1425    for (i = 0; i < num_roles; i++)
1426    {
1427       role = mmalomx_registry_component_roles(registry_id, i);
1428       if (!role || !mmalomx_role_to_name(role))
1429          break;
1430
1431       if(roles)
1432       {
1433          strncpy((char *)roles[i], mmalomx_role_to_name(role), OMX_MAX_STRINGNAME_SIZE);
1434          LOG_DEBUG("found role: %s", roles[i]);
1435       }
1436    }
1437    LOG_DEBUG("found %i roles", (int)i);
1438    *pNumRoles = i;
1439
1440    return OMX_ErrorNone;
1441 }
1442
1443 /*****************************************************************************/
1444 OMX_API OMX_ERRORTYPE MMALOMX_EXPORT(OMX_GetComponentsOfRole)(
1445    OMX_STRING role,
1446    OMX_U32 *pNumComps,
1447    OMX_U8  **compNames)
1448 {
1449    OMX_ERRORTYPE status;
1450    OMX_HANDLETYPE handle;
1451    OMX_COMPONENTTYPE *comp;
1452    OMX_U8 name[OMX_MAX_STRINGNAME_SIZE], compRole[OMX_MAX_STRINGNAME_SIZE];
1453    OMX_U32 nNameLength = OMX_MAX_STRINGNAME_SIZE, nIndex = 0;
1454    OMX_U32 nRoles, nIndexRoles, nComps = 0;
1455    OMX_CALLBACKTYPE callbacks = {0,0,0};
1456
1457    LOG_TRACE("role %s, pNumComps %p, compNames %p", role, pNumComps, compNames);
1458
1459    /* Sanity checks */
1460    if (!role || !pNumComps)
1461       return OMX_ErrorBadParameter;
1462
1463    /* Enumerates components */
1464    while ((status = OMX_ComponentNameEnum((OMX_STRING)name, nNameLength,
1465                                           nIndex++)) == OMX_ErrorNone)
1466    {
1467       /* Find component */
1468       status = MMALOMX_IMPORT(OMX_GetHandle)(&handle, (OMX_STRING)name, 0, &callbacks);
1469       if(status != OMX_ErrorNone) continue;
1470       comp = (OMX_COMPONENTTYPE *)handle;
1471
1472       /* Enumerate Roles */
1473       status = MMALOMX_IMPORT(OMX_GetRolesOfComponent)((OMX_STRING)name, &nRoles, 0);
1474       if(status != OMX_ErrorNone) continue;
1475
1476       for (nIndexRoles = 0; nIndexRoles < nRoles; nIndexRoles++)
1477       {
1478          status = comp->ComponentRoleEnum(handle, compRole, nIndexRoles);
1479          if(status != OMX_ErrorNone) break;
1480
1481          if(!strncmp((char *)role, (char *)compRole, OMX_MAX_STRINGNAME_SIZE))
1482          {
1483             /* Found one */
1484             nComps++;
1485
1486             if(!compNames) break;
1487
1488             /* Check if enough space was provided for all the component names */
1489             if(nComps > *pNumComps) return OMX_ErrorBadParameter;
1490
1491             strncpy((char *)compNames[nComps-1], (char *)name, OMX_MAX_STRINGNAME_SIZE);
1492
1493             LOG_DEBUG("found component: %s", name);
1494          }
1495       }
1496
1497       MMALOMX_IMPORT(OMX_FreeHandle)(handle);
1498    }
1499    LOG_DEBUG("found %i components", (int)nComps);
1500    *pNumComps = nComps;
1501
1502    return OMX_ErrorNone;
1503 }
1504
1505 /*****************************************************************************/
1506 OMX_API OMX_ERRORTYPE OMX_APIENTRY MMALOMX_EXPORT(OMX_SetupTunnel)(
1507    OMX_HANDLETYPE hOutput,
1508    OMX_U32 nPortOutput,
1509    OMX_HANDLETYPE hInput,
1510    OMX_U32 nPortInput)
1511 {
1512    OMX_TUNNELSETUPTYPE tunnel_setup = {0, OMX_BufferSupplyUnspecified};
1513    OMX_ERRORTYPE status = OMX_ErrorNone;
1514
1515    LOG_TRACE("hOutput %p, nPortOutput %d, hInput %p, nPortInput %d",
1516              hOutput, (int)nPortOutput, hInput, (int)nPortInput);
1517
1518    /* Sanity checks */
1519    if (!hOutput && !hInput)
1520       return OMX_ErrorBadParameter;
1521
1522    if (hOutput)
1523    {
1524       status = ((OMX_COMPONENTTYPE *)hOutput)->ComponentTunnelRequest(
1525          hOutput, nPortOutput, hInput, nPortInput, &tunnel_setup);
1526       if (status != OMX_ErrorNone)
1527          LOG_DEBUG("OMX_SetupTunnel failed on output port (%i)", status);
1528    }
1529
1530    if (status == OMX_ErrorNone && hInput)
1531    {
1532       status = ((OMX_COMPONENTTYPE *)hInput)->ComponentTunnelRequest(
1533          hInput, nPortInput, hOutput, nPortOutput, &tunnel_setup);
1534       if (status != OMX_ErrorNone)
1535       {
1536          LOG_DEBUG("OMX_SetupTunnel failed on input port (%i)", status);
1537          /* Cancel request on output port */
1538          if (hOutput)
1539             ((OMX_COMPONENTTYPE *)hOutput)->ComponentTunnelRequest(
1540                hOutput, nPortOutput, NULL, 0, NULL);
1541       }
1542    }
1543
1544    return status;
1545 }
1546
1547 OMX_API OMX_ERRORTYPE MMALOMX_EXPORT(OMX_GetContentPipe)(
1548    OMX_HANDLETYPE *hPipe,
1549    OMX_STRING szURI)
1550 {
1551    MMAL_PARAM_UNUSED(hPipe);
1552    MMAL_PARAM_UNUSED(szURI);
1553
1554    LOG_TRACE("hPipe %p, szURI %s", hPipe, szURI);
1555
1556    return OMX_ErrorNotImplemented;
1557 }
1558
1559 /*****************************************************************************
1560  * Processing thread
1561  *****************************************************************************/
1562 static void *mmalomx_cmd_thread_func(void *arg)
1563 {
1564    MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)arg;
1565    VCOS_STATUS_T status;
1566
1567    while (component->cmd_thread_used)
1568    {
1569       status = vcos_semaphore_wait(&component->cmd_sema);
1570       if (status == VCOS_EAGAIN)
1571          continue;
1572       mmalomx_commands_actions_check(component);
1573    }
1574
1575    return 0;
1576 }
1577