tarinaretake

git clone https://git.tarina.org/tarinaretake
Log | Files | Refs | README | LICENSE

ilclient.c (62686B)


      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 /*
     29  * \file
     30  *
     31  * \brief This API defines helper functions for writing IL clients.
     32  *
     33  * This file defines an IL client side library.  This is useful when
     34  * writing IL clients, since there tends to be much repeated and
     35  * common code across both single and multiple clients.  This library
     36  * seeks to remove that common code and abstract some of the
     37  * interactions with components.  There is a wrapper around a
     38  * component and tunnel, and some operations can be done on lists of
     39  * these.  The callbacks from components are handled, and specific
     40  * events can be checked or waited for.
     41 */
     42 
     43 #include <stdio.h>
     44 #include <stdlib.h>
     45 #include <stdarg.h>
     46 #include <string.h>
     47 #include <ctype.h>
     48 #include <assert.h>
     49 
     50 #include "interface/vcos/vcos.h"
     51 #include "interface/vcos/vcos_logging.h"
     52 #include "interface/vmcs_host/vchost.h"
     53 
     54 #include "IL/OMX_Broadcom.h"
     55 #include "ilclient.h"
     56 
     57 #define VCOS_LOG_CATEGORY (&ilclient_log_category)
     58 
     59 #ifndef ILCLIENT_THREAD_DEFAULT_STACK_SIZE
     60 #define ILCLIENT_THREAD_DEFAULT_STACK_SIZE   (6<<10)
     61 #endif
     62 
     63 static VCOS_LOG_CAT_T ilclient_log_category;
     64 
     65 /******************************************************************************
     66 Static data and types used only in this file.
     67 ******************************************************************************/
     68 
     69 struct _ILEVENT_T {
     70    OMX_EVENTTYPE eEvent;
     71    OMX_U32 nData1;
     72    OMX_U32 nData2;
     73    OMX_PTR pEventData;
     74    struct _ILEVENT_T *next;
     75 };
     76 
     77 #define NUM_EVENTS 100
     78 struct _ILCLIENT_T {
     79    ILEVENT_T *event_list;
     80    VCOS_SEMAPHORE_T event_sema;
     81    ILEVENT_T event_rep[NUM_EVENTS];
     82 
     83    ILCLIENT_CALLBACK_T port_settings_callback;
     84    void *port_settings_callback_data;
     85    ILCLIENT_CALLBACK_T eos_callback;
     86    void *eos_callback_data;
     87    ILCLIENT_CALLBACK_T error_callback;
     88    void *error_callback_data;
     89    ILCLIENT_BUFFER_CALLBACK_T fill_buffer_done_callback;
     90    void *fill_buffer_done_callback_data;
     91    ILCLIENT_BUFFER_CALLBACK_T empty_buffer_done_callback;
     92    void *empty_buffer_done_callback_data;
     93    ILCLIENT_CALLBACK_T configchanged_callback;
     94    void *configchanged_callback_data;
     95 };
     96 
     97 struct _COMPONENT_T {
     98    OMX_HANDLETYPE comp;
     99    ILCLIENT_CREATE_FLAGS_T flags;
    100    VCOS_SEMAPHORE_T sema;
    101    VCOS_EVENT_FLAGS_T event;
    102    struct _COMPONENT_T *related;
    103    OMX_BUFFERHEADERTYPE *out_list;
    104    OMX_BUFFERHEADERTYPE *in_list;
    105    char name[32];
    106    char bufname[32];
    107    unsigned int error_mask;
    108    unsigned int private;
    109    ILEVENT_T *list;
    110    ILCLIENT_T *client;
    111 };
    112 
    113 #define random_wait()
    114 static char *states[] = {"Invalid", "Loaded", "Idle", "Executing", "Pause", "WaitingForResources"};
    115 
    116 typedef enum {
    117    ILCLIENT_ERROR_UNPOPULATED  = 0x1,
    118    ILCLIENT_ERROR_SAMESTATE    = 0x2,
    119    ILCLIENT_ERROR_BADPARAMETER = 0x4
    120 } ILERROR_MASK_T;
    121 
    122 /******************************************************************************
    123 Static functions.
    124 ******************************************************************************/
    125 
    126 static OMX_ERRORTYPE ilclient_empty_buffer_done(OMX_IN OMX_HANDLETYPE hComponent,
    127       OMX_IN OMX_PTR pAppData,
    128       OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
    129 static OMX_ERRORTYPE ilclient_empty_buffer_done_error(OMX_IN OMX_HANDLETYPE hComponent,
    130       OMX_IN OMX_PTR pAppData,
    131       OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
    132 static OMX_ERRORTYPE ilclient_fill_buffer_done(OMX_OUT OMX_HANDLETYPE hComponent,
    133       OMX_OUT OMX_PTR pAppData,
    134       OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer);
    135 static OMX_ERRORTYPE ilclient_fill_buffer_done_error(OMX_OUT OMX_HANDLETYPE hComponent,
    136       OMX_OUT OMX_PTR pAppData,
    137       OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer);
    138 static OMX_ERRORTYPE ilclient_event_handler(OMX_IN OMX_HANDLETYPE hComponent,
    139       OMX_IN OMX_PTR pAppData,
    140       OMX_IN OMX_EVENTTYPE eEvent,
    141       OMX_IN OMX_U32 nData1,
    142       OMX_IN OMX_U32 nData2,
    143       OMX_IN OMX_PTR pEventData);
    144 static void ilclient_lock_events(ILCLIENT_T *st);
    145 static void ilclient_unlock_events(ILCLIENT_T *st);
    146 
    147 /******************************************************************************
    148 Global functions
    149 ******************************************************************************/
    150 
    151 /***********************************************************
    152  * Name: ilclient_init
    153  *
    154  * Description: Creates ilclient pointer
    155  *
    156  * Returns: pointer to client structure
    157  ***********************************************************/
    158 ILCLIENT_T *ilclient_init()
    159 {
    160    ILCLIENT_T *st = vcos_malloc(sizeof(ILCLIENT_T), "ilclient");
    161    int i;
    162    
    163    if (!st)
    164       return NULL;
    165    
    166    vcos_log_set_level(VCOS_LOG_CATEGORY, VCOS_LOG_WARN);
    167    vcos_log_register("ilclient", VCOS_LOG_CATEGORY);
    168 
    169    memset(st, 0, sizeof(ILCLIENT_T));
    170 
    171    i = vcos_semaphore_create(&st->event_sema, "il:event", 1);
    172    vc_assert(i == VCOS_SUCCESS);
    173 
    174    ilclient_lock_events(st);
    175    st->event_list = NULL;
    176    for (i=0; i<NUM_EVENTS; i++)
    177    {
    178       st->event_rep[i].eEvent = -1; // mark as unused
    179       st->event_rep[i].next = st->event_list;
    180       st->event_list = st->event_rep+i;
    181    }
    182    ilclient_unlock_events(st);
    183    return st;
    184 }
    185 
    186 /***********************************************************
    187  * Name: ilclient_destroy
    188  *
    189  * Description: frees client state
    190  *
    191  * Returns: void
    192  ***********************************************************/
    193 void ilclient_destroy(ILCLIENT_T *st)
    194 {
    195    vcos_semaphore_delete(&st->event_sema);
    196    vcos_free(st);
    197    vcos_log_unregister(VCOS_LOG_CATEGORY);
    198 }
    199 
    200 /***********************************************************
    201  * Name: ilclient_set_port_settings_callback
    202  *
    203  * Description: sets the callback used when receiving port settings
    204  * changed messages.  The data field in the callback function will be
    205  * the port index reporting the message.
    206  *
    207  * Returns: void
    208  ***********************************************************/
    209 void ilclient_set_port_settings_callback(ILCLIENT_T *st, ILCLIENT_CALLBACK_T func, void *userdata)
    210 {
    211    st->port_settings_callback = func;
    212    st->port_settings_callback_data = userdata;
    213 }
    214 
    215 /***********************************************************
    216  * Name: ilclient_set_eos_callback
    217  *
    218  * Description: sets the callback used when receiving eos flags.  The
    219  * data parameter in the callback function will be the port index
    220  * reporting an eos flag.
    221  *
    222  * Returns: void
    223  ***********************************************************/
    224 void ilclient_set_eos_callback(ILCLIENT_T *st, ILCLIENT_CALLBACK_T func, void *userdata)
    225 {
    226    st->eos_callback = func;
    227    st->eos_callback_data = userdata;
    228 }
    229 
    230 /***********************************************************
    231  * Name: ilclient_set_error_callback
    232  *
    233  * Description: sets the callback used when receiving error events.
    234  * The data parameter in the callback function will be the error code
    235  * being reported.
    236  *
    237  * Returns: void
    238  ***********************************************************/
    239 void ilclient_set_error_callback(ILCLIENT_T *st, ILCLIENT_CALLBACK_T func, void *userdata)
    240 {
    241    st->error_callback = func;
    242    st->error_callback_data = userdata;
    243 }
    244 
    245 /***********************************************************
    246  * Name: ilclient_set_fill_buffer_done_callback
    247  *
    248  * Description: sets the callback used when receiving
    249  * fill_buffer_done event
    250  *
    251  * Returns: void
    252  ***********************************************************/
    253 void ilclient_set_fill_buffer_done_callback(ILCLIENT_T *st, ILCLIENT_BUFFER_CALLBACK_T func, void *userdata)
    254 {
    255    st->fill_buffer_done_callback = func;
    256    st->fill_buffer_done_callback_data = userdata;
    257 }
    258 
    259 /***********************************************************
    260  * Name: ilclient_set_empty_buffer_done_callback
    261  *
    262  * Description: sets the callback used when receiving
    263  * empty_buffer_done event
    264  *
    265  * Returns: void
    266  ***********************************************************/
    267 void ilclient_set_empty_buffer_done_callback(ILCLIENT_T *st, ILCLIENT_BUFFER_CALLBACK_T func, void *userdata)
    268 {
    269    st->empty_buffer_done_callback = func;
    270    st->empty_buffer_done_callback_data = userdata;
    271 }
    272 
    273 /***********************************************************
    274  * Name: ilclient_set_configchanged_callback
    275  *
    276  * Description: sets the callback used when a config changed
    277  * event is received
    278  *
    279  * Returns: void
    280  ***********************************************************/
    281 void ilclient_set_configchanged_callback(ILCLIENT_T *st, ILCLIENT_CALLBACK_T func, void *userdata)
    282 {
    283    st->configchanged_callback = func;
    284    st->configchanged_callback_data = userdata;
    285 }
    286 
    287 /***********************************************************
    288  * Name: ilclient_create_component
    289  *
    290  * Description: initialises a component state structure and creates
    291  * the IL component.
    292  *
    293  * Returns: 0 on success, -1 on failure
    294  ***********************************************************/
    295 int ilclient_create_component(ILCLIENT_T *client, COMPONENT_T **comp, char *name,
    296                               ILCLIENT_CREATE_FLAGS_T flags)
    297 {
    298    OMX_CALLBACKTYPE callbacks;
    299    OMX_ERRORTYPE error;
    300    char component_name[128];
    301    int32_t status;
    302 
    303    *comp = vcos_malloc(sizeof(COMPONENT_T), "il:comp");
    304    if(!*comp)
    305       return -1;
    306 
    307    memset(*comp, 0, sizeof(COMPONENT_T));
    308 
    309 #define COMP_PREFIX "OMX.broadcom."
    310 
    311    status = vcos_event_flags_create(&(*comp)->event,"il:comp");
    312    vc_assert(status == VCOS_SUCCESS);
    313    status = vcos_semaphore_create(&(*comp)->sema, "il:comp", 1);
    314    vc_assert(status == VCOS_SUCCESS);
    315    (*comp)->client = client;
    316 
    317    vcos_snprintf((*comp)->name, sizeof((*comp)->name), "cl:%s", name);
    318    vcos_snprintf((*comp)->bufname, sizeof((*comp)->bufname), "cl:%s buffer", name);
    319    vcos_snprintf(component_name, sizeof(component_name), "%s%s", COMP_PREFIX, name);
    320 
    321    (*comp)->flags = flags;
    322 
    323    callbacks.EventHandler = ilclient_event_handler;
    324    callbacks.EmptyBufferDone = flags & ILCLIENT_ENABLE_INPUT_BUFFERS ? ilclient_empty_buffer_done : ilclient_empty_buffer_done_error;
    325    callbacks.FillBufferDone = flags & ILCLIENT_ENABLE_OUTPUT_BUFFERS ? ilclient_fill_buffer_done : ilclient_fill_buffer_done_error;
    326 
    327    error = OMX_GetHandle(&(*comp)->comp, component_name, *comp, &callbacks);
    328 
    329    if (error == OMX_ErrorNone)
    330    {
    331       OMX_UUIDTYPE uid;
    332       char name[128];
    333       OMX_VERSIONTYPE compVersion, specVersion;
    334 
    335       if(OMX_GetComponentVersion((*comp)->comp, name, &compVersion, &specVersion, &uid) == OMX_ErrorNone)
    336       {
    337          char *p = (char *) uid + strlen(COMP_PREFIX);
    338 
    339          vcos_snprintf((*comp)->name, sizeof((*comp)->name), "cl:%s", p);
    340          (*comp)->name[sizeof((*comp)->name)-1] = 0;
    341          vcos_snprintf((*comp)->bufname, sizeof((*comp)->bufname), "cl:%s buffer", p);
    342          (*comp)->bufname[sizeof((*comp)->bufname)-1] = 0;
    343       }
    344 
    345       if(flags & (ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_OUTPUT_ZERO_BUFFERS))
    346       {
    347          OMX_PORT_PARAM_TYPE ports;
    348          OMX_INDEXTYPE types[] = {OMX_IndexParamAudioInit, OMX_IndexParamVideoInit, OMX_IndexParamImageInit, OMX_IndexParamOtherInit};
    349          int i;
    350 
    351          ports.nSize = sizeof(OMX_PORT_PARAM_TYPE);
    352          ports.nVersion.nVersion = OMX_VERSION;
    353 
    354          for(i=0; i<4; i++)
    355          {
    356             OMX_ERRORTYPE error = OMX_GetParameter((*comp)->comp, types[i], &ports);
    357             if(error == OMX_ErrorNone)
    358             {
    359                uint32_t j;
    360                for(j=0; j<ports.nPorts; j++)
    361                {
    362                   if(flags & ILCLIENT_DISABLE_ALL_PORTS)
    363                      ilclient_disable_port(*comp, ports.nStartPortNumber+j);
    364                   
    365                   if(flags & ILCLIENT_OUTPUT_ZERO_BUFFERS)
    366                   {
    367                      OMX_PARAM_PORTDEFINITIONTYPE portdef;
    368                      portdef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
    369                      portdef.nVersion.nVersion = OMX_VERSION;
    370                      portdef.nPortIndex = ports.nStartPortNumber+j;
    371                      if(OMX_GetParameter((*comp)->comp, OMX_IndexParamPortDefinition, &portdef) == OMX_ErrorNone)
    372                      {
    373                         if(portdef.eDir == OMX_DirOutput && portdef.nBufferCountActual > 0)
    374                         {
    375                            portdef.nBufferCountActual = 0;
    376                            OMX_SetParameter((*comp)->comp, OMX_IndexParamPortDefinition, &portdef);
    377                         }
    378                      }
    379                   }
    380                }
    381             }
    382          }
    383       }
    384       return 0;
    385    }
    386    else
    387    {
    388       vcos_event_flags_delete(&(*comp)->event);
    389       vcos_semaphore_delete(&(*comp)->sema);
    390       vcos_free(*comp);
    391       *comp = NULL;
    392       return -1;
    393    }
    394 }
    395 
    396 /***********************************************************
    397  * Name: ilclient_remove_event
    398  *
    399  * Description: Removes an event from a component event list.  ignore1
    400  * and ignore2 are flags indicating whether to not match on nData1 and
    401  * nData2 respectively.
    402  *
    403  * Returns: 0 if the event was removed.  -1 if no matching event was
    404  * found.
    405  ***********************************************************/
    406 int ilclient_remove_event(COMPONENT_T *st, OMX_EVENTTYPE eEvent,
    407                           OMX_U32 nData1, int ignore1, OMX_IN OMX_U32 nData2, int ignore2)
    408 {
    409    ILEVENT_T *cur, *prev;
    410    uint32_t set;
    411    ilclient_lock_events(st->client);
    412 
    413    cur = st->list;
    414    prev = NULL;
    415 
    416    while (cur && !(cur->eEvent == eEvent && (ignore1 || cur->nData1 == nData1) && (ignore2 || cur->nData2 == nData2)))
    417    {
    418       prev = cur;
    419       cur = cur->next;
    420    }
    421 
    422    if (cur == NULL)
    423    {
    424       ilclient_unlock_events(st->client);
    425       return -1;
    426    }
    427 
    428    if (prev == NULL)
    429       st->list = cur->next;
    430    else
    431       prev->next = cur->next;
    432 
    433    // add back into spare list
    434    cur->next = st->client->event_list;
    435    st->client->event_list = cur;
    436    cur->eEvent = -1; // mark as unused
    437 
    438    // if we're removing an OMX_EventError or OMX_EventParamOrConfigChanged event, then clear the error bit from the eventgroup,
    439    // since the user might have been notified through the error callback, and then 
    440    // can't clear the event bit - this will then cause problems the next time they
    441    // wait for an error.
    442    if(eEvent == OMX_EventError)
    443       vcos_event_flags_get(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR_CONSUME, 0, &set);
    444    else if(eEvent == OMX_EventParamOrConfigChanged)
    445       vcos_event_flags_get(&st->event, ILCLIENT_CONFIG_CHANGED, VCOS_OR_CONSUME, 0, &set);
    446 
    447    ilclient_unlock_events(st->client);
    448    return 0;
    449 }
    450 
    451 /***********************************************************
    452  * Name: ilclient_state_transition
    453  *
    454  * Description: Transitions a null terminated list of IL components to
    455  * a given state.  All components are told to transition in a random
    456  * order before any are checked for transition completion.
    457  *
    458  * Returns: void
    459  ***********************************************************/
    460 void ilclient_state_transition(COMPONENT_T *list[], OMX_STATETYPE state)
    461 {
    462    OMX_ERRORTYPE error;
    463    int i, num;
    464    uint32_t set;
    465 
    466    num=0;
    467    while (list[num])
    468       num++;
    469 
    470    // if we transition the supplier port first, it will call freebuffer on the non
    471    // supplier, which will correctly signal a port unpopulated error.  We want to
    472    // ignore these errors.
    473    if (state == OMX_StateLoaded)
    474       for (i=0; i<num; i++)
    475          list[i]->error_mask |= ILCLIENT_ERROR_UNPOPULATED;
    476    for (i=0; i<num; i++)
    477       list[i]->private = ((rand() >> 13) & 0xff)+1;
    478 
    479    for (i=0; i<num; i++)
    480    {
    481       // transition the components in a random order
    482       int j, min = -1;
    483       for (j=0; j<num; j++)
    484          if (list[j]->private && (min == -1 || list[min]->private > list[j]->private))
    485             min = j;
    486 
    487       list[min]->private = 0;
    488 
    489       random_wait();
    490       //Clear error event for this component
    491       vcos_event_flags_get(&list[min]->event, ILCLIENT_EVENT_ERROR, VCOS_OR_CONSUME, 0, &set);
    492 
    493       error = OMX_SendCommand(list[min]->comp, OMX_CommandStateSet, state, NULL);
    494       vc_assert(error == OMX_ErrorNone);
    495    }
    496 
    497    random_wait();
    498 
    499    for (i=0; i<num; i++)
    500       if(ilclient_wait_for_command_complete(list[i], OMX_CommandStateSet, state) < 0)
    501          vc_assert(0);
    502 
    503    if (state == OMX_StateLoaded)
    504       for (i=0; i<num; i++)
    505          list[i]->error_mask &= ~ILCLIENT_ERROR_UNPOPULATED;
    506 }
    507 
    508 /***********************************************************
    509  * Name: ilclient_teardown_tunnels
    510  *
    511  * Description: tears down a null terminated list of tunnels.
    512  *
    513  * Returns: void
    514  ***********************************************************/
    515 void ilclient_teardown_tunnels(TUNNEL_T *tunnel)
    516 {
    517    int i;
    518    OMX_ERRORTYPE error;
    519 
    520    i=0;;
    521    while (tunnel[i].source)
    522    {
    523       error = OMX_SetupTunnel(tunnel[i].source->comp, tunnel[i].source_port, NULL, 0);
    524       vc_assert(error == OMX_ErrorNone);
    525 
    526       error = OMX_SetupTunnel(tunnel[i].sink->comp, tunnel[i].sink_port, NULL, 0);
    527       vc_assert(error == OMX_ErrorNone);
    528       i++;
    529    }
    530 }
    531 
    532 /***********************************************************
    533  * Name: ilclient_disable_tunnel
    534  *
    535  * Description: disables a tunnel by disabling the ports.  Allows
    536  * ports to signal same state error if they were already disabled.
    537  *
    538  * Returns: void
    539  ***********************************************************/
    540 void ilclient_disable_tunnel(TUNNEL_T *tunnel)
    541 {
    542    OMX_ERRORTYPE error;
    543    
    544    if(tunnel->source == 0 || tunnel->sink == 0)
    545       return;
    546 
    547    tunnel->source->error_mask |= ILCLIENT_ERROR_UNPOPULATED;
    548    tunnel->sink->error_mask |= ILCLIENT_ERROR_UNPOPULATED;
    549 
    550    error = OMX_SendCommand(tunnel->source->comp, OMX_CommandPortDisable, tunnel->source_port, NULL);
    551    vc_assert(error == OMX_ErrorNone);
    552 
    553    error = OMX_SendCommand(tunnel->sink->comp, OMX_CommandPortDisable, tunnel->sink_port, NULL);
    554    vc_assert(error == OMX_ErrorNone);
    555 
    556    if(ilclient_wait_for_command_complete(tunnel->source, OMX_CommandPortDisable, tunnel->source_port) < 0)
    557       vc_assert(0);
    558 
    559    if(ilclient_wait_for_command_complete(tunnel->sink, OMX_CommandPortDisable, tunnel->sink_port) < 0)
    560       vc_assert(0);
    561 
    562    tunnel->source->error_mask &= ~ILCLIENT_ERROR_UNPOPULATED;
    563    tunnel->sink->error_mask &= ~ILCLIENT_ERROR_UNPOPULATED;
    564 }
    565 
    566 /***********************************************************
    567  * Name: ilclient_enable_tunnel
    568  *
    569  * Description: enables a tunnel by enabling the ports
    570  *
    571  * Returns: 0 on success, -1 on failure
    572  ***********************************************************/
    573 int ilclient_enable_tunnel(TUNNEL_T *tunnel)
    574 {
    575    OMX_STATETYPE state;
    576    OMX_ERRORTYPE error;
    577 
    578    ilclient_debug_output("ilclient: enable tunnel from %x/%d to %x/%d",
    579                          tunnel->source, tunnel->source_port,
    580                          tunnel->sink, tunnel->sink_port);
    581 
    582    error = OMX_SendCommand(tunnel->source->comp, OMX_CommandPortEnable, tunnel->source_port, NULL);
    583    vc_assert(error == OMX_ErrorNone);
    584 
    585    error = OMX_SendCommand(tunnel->sink->comp, OMX_CommandPortEnable, tunnel->sink_port, NULL);
    586    vc_assert(error == OMX_ErrorNone);
    587 
    588    // to complete, the sink component can't be in loaded state
    589    error = OMX_GetState(tunnel->sink->comp, &state);
    590    vc_assert(error == OMX_ErrorNone);
    591    if (state == OMX_StateLoaded)
    592    {
    593       int ret = 0;
    594 
    595       if(ilclient_wait_for_command_complete(tunnel->sink, OMX_CommandPortEnable, tunnel->sink_port) != 0 ||
    596          OMX_SendCommand(tunnel->sink->comp, OMX_CommandStateSet, OMX_StateIdle, NULL) != OMX_ErrorNone ||
    597          (ret = ilclient_wait_for_command_complete_dual(tunnel->sink, OMX_CommandStateSet, OMX_StateIdle, tunnel->source)) < 0)
    598       {
    599          if(ret == -2)
    600          {
    601             // the error was reported fom the source component: clear this error and disable the sink component
    602             ilclient_wait_for_command_complete(tunnel->source, OMX_CommandPortEnable, tunnel->source_port);
    603             ilclient_disable_port(tunnel->sink, tunnel->sink_port);
    604          }
    605 
    606          ilclient_debug_output("ilclient: could not change component state to IDLE");
    607          ilclient_disable_port(tunnel->source, tunnel->source_port);
    608          return -1;
    609       }
    610    }
    611    else
    612    {
    613       if (ilclient_wait_for_command_complete(tunnel->sink, OMX_CommandPortEnable, tunnel->sink_port) != 0)
    614       {
    615          ilclient_debug_output("ilclient: could not change sink port %d to enabled", tunnel->sink_port);
    616 
    617          //Oops failed to enable the sink port
    618          ilclient_disable_port(tunnel->source, tunnel->source_port);
    619          //Clean up the port enable event from the source port.
    620          ilclient_wait_for_event(tunnel->source, OMX_EventCmdComplete,
    621                                  OMX_CommandPortEnable, 0, tunnel->source_port, 0,
    622                                  ILCLIENT_PORT_ENABLED | ILCLIENT_EVENT_ERROR, VCOS_EVENT_FLAGS_SUSPEND);
    623          return -1;
    624       }
    625    }
    626 
    627    if(ilclient_wait_for_command_complete(tunnel->source, OMX_CommandPortEnable, tunnel->source_port) != 0)
    628    {
    629       ilclient_debug_output("ilclient: could not change source port %d to enabled", tunnel->source_port);
    630 
    631       //Failed to enable the source port
    632       ilclient_disable_port(tunnel->sink, tunnel->sink_port);
    633       return -1;
    634    }
    635 
    636    return 0;
    637 }
    638 
    639 
    640 /***********************************************************
    641  * Name: ilclient_flush_tunnels
    642  *
    643  * Description: flushes all ports used in a null terminated list of
    644  * tunnels.  max specifies the maximum number of tunnels to flush from
    645  * the list, where max=0 means all tunnels.
    646  *
    647  * Returns: void
    648  ***********************************************************/
    649 void ilclient_flush_tunnels(TUNNEL_T *tunnel, int max)
    650 {
    651    OMX_ERRORTYPE error;
    652    int i;
    653 
    654    i=0;
    655    while (tunnel[i].source && (max == 0 || i < max))
    656    {
    657       error = OMX_SendCommand(tunnel[i].source->comp, OMX_CommandFlush, tunnel[i].source_port, NULL);
    658       vc_assert(error == OMX_ErrorNone);
    659 
    660       error = OMX_SendCommand(tunnel[i].sink->comp, OMX_CommandFlush, tunnel[i].sink_port, NULL);
    661       vc_assert(error == OMX_ErrorNone);
    662 
    663       ilclient_wait_for_event(tunnel[i].source, OMX_EventCmdComplete,
    664                               OMX_CommandFlush, 0, tunnel[i].source_port, 0,
    665                               ILCLIENT_PORT_FLUSH, VCOS_EVENT_FLAGS_SUSPEND);
    666       ilclient_wait_for_event(tunnel[i].sink, OMX_EventCmdComplete,
    667                               OMX_CommandFlush, 0, tunnel[i].sink_port, 0,
    668                               ILCLIENT_PORT_FLUSH, VCOS_EVENT_FLAGS_SUSPEND);
    669       i++;
    670    }
    671 }
    672 
    673 
    674 /***********************************************************
    675  * Name: ilclient_return_events
    676  *
    677  * Description: Returns all events from a component event list to the
    678  * list of unused event structures.
    679  *
    680  * Returns: void
    681  ***********************************************************/
    682 void ilclient_return_events(COMPONENT_T *comp)
    683 {
    684    ilclient_lock_events(comp->client);
    685    while (comp->list)
    686    {
    687       ILEVENT_T *next = comp->list->next;
    688       comp->list->next = comp->client->event_list;
    689       comp->client->event_list = comp->list;
    690       comp->list = next;
    691    }
    692    ilclient_unlock_events(comp->client);
    693 }
    694 
    695 /***********************************************************
    696  * Name: ilclient_cleanup_components
    697  *
    698  * Description: frees all components from a null terminated list and
    699  * deletes resources used in component state structure.
    700  *
    701  * Returns: void
    702  ***********************************************************/
    703 void ilclient_cleanup_components(COMPONENT_T *list[])
    704 {
    705    int i;
    706    OMX_ERRORTYPE error;
    707 
    708    i=0;
    709    while (list[i])
    710    {
    711       ilclient_return_events(list[i]);
    712       if (list[i]->comp)
    713       {
    714          error = OMX_FreeHandle(list[i]->comp);
    715 
    716          vc_assert(error == OMX_ErrorNone);
    717       }
    718       i++;
    719    }
    720 
    721    i=0;
    722    while (list[i])
    723    {
    724       vcos_event_flags_delete(&list[i]->event);
    725       vcos_semaphore_delete(&list[i]->sema);
    726       vcos_free(list[i]);
    727       list[i] = NULL;
    728       i++;
    729    }
    730 }
    731 
    732 /***********************************************************
    733  * Name: ilclient_change_component_state
    734  *
    735  * Description: changes the state of a single component.  Note: this
    736  * may not be suitable if the component is tunnelled and requires
    737  * connected components to also change state.
    738  *
    739  * Returns: 0 on success, -1 on failure (note - trying to change to
    740  * the same state which causes a OMX_ErrorSameState is treated as
    741  * success)
    742  ***********************************************************/
    743 int ilclient_change_component_state(COMPONENT_T *comp, OMX_STATETYPE state)
    744 {
    745    OMX_ERRORTYPE error;
    746    error = OMX_SendCommand(comp->comp, OMX_CommandStateSet, state, NULL);
    747    vc_assert(error == OMX_ErrorNone);
    748    if(ilclient_wait_for_command_complete(comp, OMX_CommandStateSet, state) < 0)
    749    {
    750       ilclient_debug_output("ilclient: could not change component state to %d", state);
    751       ilclient_remove_event(comp, OMX_EventError, 0, 1, 0, 1);
    752       return -1;
    753    }
    754    return 0;
    755 }
    756 
    757 /***********************************************************
    758  * Name: ilclient_disable_port
    759  *
    760  * Description: disables a port on a given component.
    761  *
    762  * Returns: void
    763  ***********************************************************/
    764 void ilclient_disable_port(COMPONENT_T *comp, int portIndex)
    765 {
    766    OMX_ERRORTYPE error;
    767    error = OMX_SendCommand(comp->comp, OMX_CommandPortDisable, portIndex, NULL);
    768    vc_assert(error == OMX_ErrorNone);
    769    if(ilclient_wait_for_command_complete(comp, OMX_CommandPortDisable, portIndex) < 0)
    770       vc_assert(0);
    771 }
    772 
    773 /***********************************************************
    774  * Name: ilclient_enabled_port
    775  *
    776  * Description: enables a port on a given component.
    777  *
    778  * Returns: void
    779  ***********************************************************/
    780 void ilclient_enable_port(COMPONENT_T *comp, int portIndex)
    781 {
    782    OMX_ERRORTYPE error;
    783    error = OMX_SendCommand(comp->comp, OMX_CommandPortEnable, portIndex, NULL);
    784    vc_assert(error == OMX_ErrorNone);
    785    if(ilclient_wait_for_command_complete(comp, OMX_CommandPortEnable, portIndex) < 0)
    786       vc_assert(0);
    787 }
    788 
    789 
    790 /***********************************************************
    791  * Name: ilclient_enable_port_buffers
    792  *
    793  * Description: enables a port on a given component which requires
    794  * buffers to be supplied by the client.
    795  *
    796  * Returns: void
    797  ***********************************************************/
    798 int ilclient_enable_port_buffers(COMPONENT_T *comp, int portIndex,
    799                                  ILCLIENT_MALLOC_T ilclient_malloc,
    800                                  ILCLIENT_FREE_T ilclient_free,
    801                                  void *private)
    802 {
    803    OMX_ERRORTYPE error;
    804    OMX_PARAM_PORTDEFINITIONTYPE portdef;
    805    OMX_BUFFERHEADERTYPE *list = NULL, **end = &list;
    806    OMX_STATETYPE state;
    807    int i;
    808 
    809    memset(&portdef, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
    810    portdef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
    811    portdef.nVersion.nVersion = OMX_VERSION;
    812    portdef.nPortIndex = portIndex;
    813    
    814    // work out buffer requirements, check port is in the right state
    815    error = OMX_GetParameter(comp->comp, OMX_IndexParamPortDefinition, &portdef);
    816    if(error != OMX_ErrorNone || portdef.bEnabled != OMX_FALSE || portdef.nBufferCountActual == 0 || portdef.nBufferSize == 0)
    817       return -1;
    818 
    819    // check component is in the right state to accept buffers
    820    error = OMX_GetState(comp->comp, &state);
    821    if (error != OMX_ErrorNone || !(state == OMX_StateIdle || state == OMX_StateExecuting || state == OMX_StatePause))
    822       return -1;
    823 
    824    // send the command
    825    error = OMX_SendCommand(comp->comp, OMX_CommandPortEnable, portIndex, NULL);
    826    vc_assert(error == OMX_ErrorNone);
    827 
    828    for (i=0; i != portdef.nBufferCountActual; i++)
    829    {
    830       unsigned char *buf;
    831       if(ilclient_malloc)
    832          buf = ilclient_malloc(private, portdef.nBufferSize, portdef.nBufferAlignment, comp->bufname);
    833       else
    834          buf = vcos_malloc_aligned(portdef.nBufferSize, portdef.nBufferAlignment, comp->bufname);
    835 
    836       if(!buf)
    837          break;
    838 
    839       error = OMX_UseBuffer(comp->comp, end, portIndex, NULL, portdef.nBufferSize, buf);
    840       if(error != OMX_ErrorNone)
    841       {
    842          if(ilclient_free)
    843             ilclient_free(private, buf);
    844          else
    845             vcos_free(buf);
    846 
    847          break;
    848       }
    849       end = (OMX_BUFFERHEADERTYPE **) &((*end)->pAppPrivate);
    850    }
    851 
    852    // queue these buffers
    853    vcos_semaphore_wait(&comp->sema);
    854 
    855    if(portdef.eDir == OMX_DirInput)
    856    {
    857       *end = comp->in_list;
    858       comp->in_list = list;
    859    }
    860    else
    861    {
    862       *end = comp->out_list;
    863       comp->out_list = list;
    864    }
    865 
    866    vcos_semaphore_post(&comp->sema);
    867 
    868    if(i != portdef.nBufferCountActual ||
    869       ilclient_wait_for_command_complete(comp, OMX_CommandPortEnable, portIndex) < 0)
    870    {
    871       ilclient_disable_port_buffers(comp, portIndex, NULL, ilclient_free, private);
    872 
    873       // at this point the first command might have terminated with an error, which means that
    874       // the port is disabled before the disable_port_buffers function is called, so we're left
    875       // with the error bit set and an error event in the queue.  Clear these now if they exist.
    876       ilclient_remove_event(comp, OMX_EventError, 0, 1, 1, 0);
    877 
    878       return -1;
    879    }
    880 
    881    // success
    882    return 0;
    883 }
    884 
    885 
    886 /***********************************************************
    887  * Name: ilclient_disable_port_buffers
    888  *
    889  * Description: disables a port on a given component which has
    890  * buffers supplied by the client.
    891  *
    892  * Returns: void
    893  ***********************************************************/
    894 void ilclient_disable_port_buffers(COMPONENT_T *comp, int portIndex,
    895                                    OMX_BUFFERHEADERTYPE *bufferList,
    896                                    ILCLIENT_FREE_T ilclient_free,
    897                                    void *private)
    898 {
    899    OMX_ERRORTYPE error;
    900    OMX_BUFFERHEADERTYPE *list = bufferList;
    901    OMX_BUFFERHEADERTYPE **head, *clist, *prev;
    902    OMX_PARAM_PORTDEFINITIONTYPE portdef;
    903    int num;
    904 
    905    // get the buffers off the relevant queue
    906    memset(&portdef, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
    907    portdef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
    908    portdef.nVersion.nVersion = OMX_VERSION;
    909    portdef.nPortIndex = portIndex;
    910    
    911    // work out buffer requirements, check port is in the right state
    912    error = OMX_GetParameter(comp->comp, OMX_IndexParamPortDefinition, &portdef);
    913    if(error != OMX_ErrorNone || portdef.bEnabled != OMX_TRUE || portdef.nBufferCountActual == 0 || portdef.nBufferSize == 0)
    914       return;
    915    
    916    num = portdef.nBufferCountActual;
    917    
    918    error = OMX_SendCommand(comp->comp, OMX_CommandPortDisable, portIndex, NULL);
    919    vc_assert(error == OMX_ErrorNone);
    920       
    921    while(num > 0)
    922    {
    923       VCOS_UNSIGNED set;
    924 
    925       if(list == NULL)
    926       {
    927          vcos_semaphore_wait(&comp->sema);
    928          
    929          // take buffers for this port off the relevant queue
    930          head = portdef.eDir == OMX_DirInput ? &comp->in_list : &comp->out_list;
    931          clist = *head;
    932          prev = NULL;
    933          
    934          while(clist)
    935          {
    936             if((portdef.eDir == OMX_DirInput ? clist->nInputPortIndex : clist->nOutputPortIndex) == portIndex)
    937             {
    938                OMX_BUFFERHEADERTYPE *pBuffer = clist;
    939                
    940                if(!prev)
    941                   clist = *head = (OMX_BUFFERHEADERTYPE *) pBuffer->pAppPrivate;
    942                else
    943                   clist = prev->pAppPrivate = (OMX_BUFFERHEADERTYPE *) pBuffer->pAppPrivate;
    944                
    945                pBuffer->pAppPrivate = list;
    946                list = pBuffer;
    947             }
    948             else
    949             {
    950                prev = clist;
    951                clist = (OMX_BUFFERHEADERTYPE *) &(clist->pAppPrivate);
    952             }
    953          }
    954          
    955          vcos_semaphore_post(&comp->sema);
    956       }
    957 
    958       while(list)
    959       {
    960          void *buf = list->pBuffer;
    961          OMX_BUFFERHEADERTYPE *next = list->pAppPrivate;
    962          
    963          error = OMX_FreeBuffer(comp->comp, portIndex, list);
    964          vc_assert(error == OMX_ErrorNone);
    965          
    966          if(ilclient_free)
    967             ilclient_free(private, buf);
    968          else
    969             vcos_free(buf);
    970          
    971          num--;
    972          list = next;
    973       }
    974 
    975       if(num)
    976       {
    977          OMX_U32 mask = ILCLIENT_PORT_DISABLED | ILCLIENT_EVENT_ERROR;
    978          mask |= (portdef.eDir == OMX_DirInput ? ILCLIENT_EMPTY_BUFFER_DONE : ILCLIENT_FILL_BUFFER_DONE);
    979 
    980          // also wait for command complete/error in case we didn't have all the buffers allocated
    981          vcos_event_flags_get(&comp->event, mask, VCOS_OR_CONSUME, -1, &set);
    982 
    983          if((set & ILCLIENT_EVENT_ERROR) && ilclient_remove_event(comp, OMX_EventError, 0, 1, 1, 0) >= 0)
    984             return;
    985 
    986          if((set & ILCLIENT_PORT_DISABLED) && ilclient_remove_event(comp, OMX_EventCmdComplete, OMX_CommandPortDisable, 0, portIndex, 0) >= 0)
    987             return;
    988       }            
    989    }
    990   
    991    if(ilclient_wait_for_command_complete(comp, OMX_CommandPortDisable, portIndex) < 0)
    992       vc_assert(0);
    993 }
    994 
    995 
    996 /***********************************************************
    997  * Name: ilclient_setup_tunnel
    998  *
    999  * Description: creates a tunnel between components that require that
   1000  * ports be inititially disabled, then enabled after tunnel setup.  If
   1001  * timeout is non-zero, it will initially wait until a port settings
   1002  * changes message has been received by the output port.  If port
   1003  * streams are supported by the output port, the requested port stream
   1004  * will be selected.
   1005  *
   1006  * Returns: 0 indicates success, negative indicates failure.
   1007  * -1: a timeout waiting for the parameter changed
   1008  * -2: an error was returned instead of parameter changed
   1009  * -3: no streams are available from this port
   1010  * -4: requested stream is not available from this port
   1011  * -5: the data format was not acceptable to the sink
   1012  ***********************************************************/
   1013 int ilclient_setup_tunnel(TUNNEL_T *tunnel, unsigned int portStream, int timeout)
   1014 {
   1015    OMX_ERRORTYPE error;
   1016    OMX_PARAM_U32TYPE param;
   1017    OMX_STATETYPE state;
   1018    int32_t status;
   1019    int enable_error;
   1020 
   1021    // source component must at least be idle, not loaded
   1022    error = OMX_GetState(tunnel->source->comp, &state);
   1023    vc_assert(error == OMX_ErrorNone);
   1024    if (state == OMX_StateLoaded && ilclient_change_component_state(tunnel->source, OMX_StateIdle) < 0)
   1025       return -2;
   1026 
   1027    // wait for the port parameter changed from the source port
   1028    if(timeout)
   1029    {
   1030       status = ilclient_wait_for_event(tunnel->source, OMX_EventPortSettingsChanged,
   1031                                        tunnel->source_port, 0, -1, 1,
   1032                                        ILCLIENT_PARAMETER_CHANGED | ILCLIENT_EVENT_ERROR, timeout);
   1033       
   1034       if (status < 0)
   1035       {
   1036          ilclient_debug_output(
   1037             "ilclient: timed out waiting for port settings changed on port %d", tunnel->source_port);
   1038          return status;
   1039       }
   1040    }
   1041 
   1042    // disable ports
   1043    ilclient_disable_tunnel(tunnel);
   1044 
   1045    // if this source port uses port streams, we need to select one of them before proceeding
   1046    // if getparameter causes an error that's fine, nothing needs selecting
   1047    param.nSize = sizeof(OMX_PARAM_U32TYPE);
   1048    param.nVersion.nVersion = OMX_VERSION;
   1049    param.nPortIndex = tunnel->source_port;
   1050    if (OMX_GetParameter(tunnel->source->comp, OMX_IndexParamNumAvailableStreams, &param) == OMX_ErrorNone)
   1051    {
   1052       if (param.nU32 == 0)
   1053       {
   1054          // no streams available
   1055          // leave the source port disabled, and return a failure
   1056          return -3;
   1057       }
   1058       if (param.nU32 <= portStream)
   1059       {
   1060          // requested stream not available
   1061          // no streams available
   1062          // leave the source port disabled, and return a failure
   1063          return -4;
   1064       }
   1065 
   1066       param.nU32 = portStream;
   1067       error = OMX_SetParameter(tunnel->source->comp, OMX_IndexParamActiveStream, &param);
   1068       vc_assert(error == OMX_ErrorNone);
   1069    }
   1070 
   1071    // now create the tunnel
   1072    error = OMX_SetupTunnel(tunnel->source->comp, tunnel->source_port, tunnel->sink->comp, tunnel->sink_port);
   1073 
   1074    enable_error = 0;
   1075 
   1076    if (error != OMX_ErrorNone || (enable_error=ilclient_enable_tunnel(tunnel)) < 0)
   1077    {
   1078       // probably format not compatible
   1079       error = OMX_SetupTunnel(tunnel->source->comp, tunnel->source_port, NULL, 0);
   1080       vc_assert(error == OMX_ErrorNone);
   1081       error = OMX_SetupTunnel(tunnel->sink->comp, tunnel->sink_port, NULL, 0);
   1082       vc_assert(error == OMX_ErrorNone);
   1083       
   1084       if(enable_error)
   1085       {
   1086          //Clean up the errors. This does risk removing an error that was nothing to do with this tunnel :-/
   1087          ilclient_remove_event(tunnel->sink, OMX_EventError, 0, 1, 0, 1);
   1088          ilclient_remove_event(tunnel->source, OMX_EventError, 0, 1, 0, 1);
   1089       }
   1090 
   1091       ilclient_debug_output("ilclient: could not setup/enable tunnel (setup=0x%x,enable=%d)",
   1092                              error, enable_error);
   1093       return -5;
   1094    }
   1095 
   1096    return 0;
   1097 }
   1098 
   1099 /***********************************************************
   1100  * Name: ilclient_wait_for_event
   1101  *
   1102  * Description: waits for a given event to appear on a component event
   1103  * list.  If not immediately present, will wait on that components
   1104  * event group for the given event flag.
   1105  *
   1106  * Returns: 0 indicates success, negative indicates failure.
   1107  * -1: a timeout was received.
   1108  * -2: an error event was received.
   1109  * -3: a config change event was received.
   1110  ***********************************************************/
   1111 int ilclient_wait_for_event(COMPONENT_T *comp, OMX_EVENTTYPE event,
   1112                             OMX_U32 nData1, int ignore1, OMX_IN OMX_U32 nData2, int ignore2,
   1113                             int event_flag, int suspend)
   1114 {
   1115    int32_t status;
   1116    uint32_t set;
   1117 
   1118    while (ilclient_remove_event(comp, event, nData1, ignore1, nData2, ignore2) < 0)
   1119    {
   1120       // if we want to be notified of errors, check the list for an error now
   1121       // before blocking, the event flag may have been cleared already.
   1122       if(event_flag & ILCLIENT_EVENT_ERROR)
   1123       {
   1124          ILEVENT_T *cur;
   1125          ilclient_lock_events(comp->client);
   1126          cur = comp->list;
   1127          while(cur && cur->eEvent != OMX_EventError)            
   1128             cur = cur->next;
   1129          
   1130          if(cur)
   1131          {
   1132             // clear error flag
   1133             vcos_event_flags_get(&comp->event, ILCLIENT_EVENT_ERROR, VCOS_OR_CONSUME, 0, &set);
   1134             ilclient_unlock_events(comp->client);
   1135             return -2;
   1136          }
   1137 
   1138          ilclient_unlock_events(comp->client);
   1139       }
   1140       // check for config change event if we are asked to be notified of that
   1141       if(event_flag & ILCLIENT_CONFIG_CHANGED)
   1142       {
   1143          ILEVENT_T *cur;
   1144          ilclient_lock_events(comp->client);
   1145          cur = comp->list;
   1146          while(cur && cur->eEvent != OMX_EventParamOrConfigChanged)
   1147             cur = cur->next;
   1148          
   1149          ilclient_unlock_events(comp->client);
   1150 
   1151          if(cur)
   1152             return ilclient_remove_event(comp, event, nData1, ignore1, nData2, ignore2) == 0 ? 0 : -3;
   1153       }
   1154 
   1155       status = vcos_event_flags_get(&comp->event, event_flag, VCOS_OR_CONSUME, 
   1156                                     suspend, &set);
   1157       if (status != 0)
   1158          return -1;
   1159       if (set & ILCLIENT_EVENT_ERROR)
   1160          return -2;
   1161       if (set & ILCLIENT_CONFIG_CHANGED)
   1162          return ilclient_remove_event(comp, event, nData1, ignore1, nData2, ignore2) == 0 ? 0 : -3;
   1163    }
   1164 
   1165    return 0;
   1166 }
   1167 
   1168 
   1169 
   1170 /***********************************************************
   1171  * Name: ilclient_wait_for_command_complete_dual
   1172  *
   1173  * Description: Waits for an event signalling command completion.  In
   1174  * this version we may also return failure if there is an error event
   1175  * that has terminated a command on a second component.
   1176  *
   1177  * Returns: 0 on success, -1 on failure of comp, -2 on failure of other
   1178  ***********************************************************/
   1179 int ilclient_wait_for_command_complete_dual(COMPONENT_T *comp, OMX_COMMANDTYPE command, OMX_U32 nData2, COMPONENT_T *other)
   1180 {
   1181    OMX_U32 mask = ILCLIENT_EVENT_ERROR;
   1182    int ret = 0;
   1183 
   1184    switch(command) {
   1185    case OMX_CommandStateSet:    mask |= ILCLIENT_STATE_CHANGED; break;
   1186    case OMX_CommandPortDisable: mask |= ILCLIENT_PORT_DISABLED; break;
   1187    case OMX_CommandPortEnable:  mask |= ILCLIENT_PORT_ENABLED;  break;
   1188    default: return -1;
   1189    }
   1190 
   1191    if(other)
   1192       other->related = comp;
   1193 
   1194    while(1)
   1195    {
   1196       ILEVENT_T *cur, *prev = NULL;
   1197       VCOS_UNSIGNED set;
   1198 
   1199       ilclient_lock_events(comp->client);
   1200 
   1201       cur = comp->list;
   1202       while(cur &&
   1203             !(cur->eEvent == OMX_EventCmdComplete && cur->nData1 == command && cur->nData2 == nData2) &&
   1204             !(cur->eEvent == OMX_EventError && cur->nData2 == 1))
   1205       {
   1206          prev = cur;
   1207          cur = cur->next;
   1208       }
   1209 
   1210       if(cur)
   1211       {
   1212          if(prev == NULL)
   1213             comp->list = cur->next;
   1214          else
   1215             prev->next = cur->next;
   1216 
   1217          // work out whether this was a success or a fail event
   1218          ret = cur->eEvent == OMX_EventCmdComplete || cur->nData1 == OMX_ErrorSameState ? 0 : -1;
   1219 
   1220          if(cur->eEvent == OMX_EventError)
   1221             vcos_event_flags_get(&comp->event, ILCLIENT_EVENT_ERROR, VCOS_OR_CONSUME, 0, &set);
   1222 
   1223          // add back into spare list
   1224          cur->next = comp->client->event_list;
   1225          comp->client->event_list = cur;
   1226          cur->eEvent = -1; // mark as unused
   1227          
   1228          ilclient_unlock_events(comp->client);
   1229          break;
   1230       }
   1231       else if(other != NULL)
   1232       {
   1233          // check the other component for an error event that terminates a command
   1234          cur = other->list;
   1235          while(cur && !(cur->eEvent == OMX_EventError && cur->nData2 == 1))
   1236             cur = cur->next;
   1237 
   1238          if(cur)
   1239          {
   1240             // we don't remove the event in this case, since the user
   1241             // can confirm that this event errored by calling wait_for_command on the
   1242             // other component
   1243 
   1244             ret = -2;
   1245             ilclient_unlock_events(comp->client);
   1246             break;
   1247          }
   1248       }
   1249 
   1250       ilclient_unlock_events(comp->client);
   1251 
   1252       vcos_event_flags_get(&comp->event, mask, VCOS_OR_CONSUME, VCOS_SUSPEND, &set);
   1253    }
   1254 
   1255    if(other)
   1256       other->related = NULL;
   1257 
   1258    return ret;
   1259 }
   1260 
   1261 
   1262 /***********************************************************
   1263  * Name: ilclient_wait_for_command_complete
   1264  *
   1265  * Description: Waits for an event signalling command completion.
   1266  *
   1267  * Returns: 0 on success, -1 on failure.
   1268  ***********************************************************/
   1269 int ilclient_wait_for_command_complete(COMPONENT_T *comp, OMX_COMMANDTYPE command, OMX_U32 nData2)
   1270 {
   1271    return ilclient_wait_for_command_complete_dual(comp, command, nData2, NULL);
   1272 }
   1273 
   1274 /***********************************************************
   1275  * Name: ilclient_get_output_buffer
   1276  *
   1277  * Description: Returns an output buffer returned from a component
   1278  * using the OMX_FillBufferDone callback from the output list for the
   1279  * given component and port index.
   1280  *
   1281  * Returns: pointer to buffer if available, otherwise NULL
   1282  ***********************************************************/
   1283 OMX_BUFFERHEADERTYPE *ilclient_get_output_buffer(COMPONENT_T *comp, int portIndex, int block)
   1284 {
   1285    OMX_BUFFERHEADERTYPE *ret = NULL, *prev = NULL;
   1286    VCOS_UNSIGNED set;
   1287 
   1288    do {
   1289       vcos_semaphore_wait(&comp->sema);
   1290       ret = comp->out_list;
   1291       while(ret != NULL && ret->nOutputPortIndex != portIndex)
   1292       {
   1293          prev = ret;
   1294          ret = ret->pAppPrivate;
   1295       }
   1296       
   1297       if(ret)
   1298       {
   1299          if(prev == NULL)
   1300             comp->out_list = ret->pAppPrivate;
   1301          else
   1302             prev->pAppPrivate = ret->pAppPrivate;
   1303          
   1304          ret->pAppPrivate = NULL;
   1305       }
   1306       vcos_semaphore_post(&comp->sema);
   1307 
   1308       if(block && !ret)
   1309          vcos_event_flags_get(&comp->event, ILCLIENT_FILL_BUFFER_DONE, VCOS_OR_CONSUME, -1, &set);
   1310 
   1311    } while(block && !ret);
   1312 
   1313    return ret;
   1314 }
   1315 
   1316 /***********************************************************
   1317  * Name: ilclient_get_input_buffer
   1318  *
   1319  * Description: Returns an input buffer return from a component using
   1320  * the OMX_EmptyBufferDone callback from the output list for the given
   1321  * component and port index.
   1322  *
   1323  * Returns: pointer to buffer if available, otherwise NULL
   1324  ***********************************************************/
   1325 OMX_BUFFERHEADERTYPE *ilclient_get_input_buffer(COMPONENT_T *comp, int portIndex, int block)
   1326 {
   1327    OMX_BUFFERHEADERTYPE *ret = NULL, *prev = NULL;
   1328 
   1329    do {
   1330       VCOS_UNSIGNED set;
   1331 
   1332       vcos_semaphore_wait(&comp->sema);
   1333       ret = comp->in_list;
   1334       while(ret != NULL && ret->nInputPortIndex != portIndex)
   1335       {
   1336          prev = ret;
   1337          ret = ret->pAppPrivate;
   1338       }
   1339       
   1340       if(ret)
   1341       {
   1342          if(prev == NULL)
   1343             comp->in_list = ret->pAppPrivate;
   1344          else
   1345             prev->pAppPrivate = ret->pAppPrivate;
   1346          
   1347          ret->pAppPrivate = NULL;
   1348       }
   1349       vcos_semaphore_post(&comp->sema);
   1350 
   1351       if(block && !ret)
   1352          vcos_event_flags_get(&comp->event, ILCLIENT_EMPTY_BUFFER_DONE, VCOS_OR_CONSUME, -1, &set);
   1353 
   1354    } while(block && !ret);
   1355 
   1356    return ret;
   1357 }
   1358 
   1359 /***********************************************************
   1360  * Name: ilclient_debug_output
   1361  *
   1362  * Description: prints a varg message to the log or the debug screen
   1363  * under win32
   1364  *
   1365  * Returns: void
   1366  ***********************************************************/
   1367 void ilclient_debug_output(char *format, ...)
   1368 {
   1369    va_list args;
   1370 
   1371    va_start(args, format);
   1372    vcos_vlog_info(format, args);
   1373    va_end(args);
   1374 }
   1375 
   1376 /******************************************************************************
   1377 Static functions
   1378 ******************************************************************************/
   1379 
   1380 /***********************************************************
   1381  * Name: ilclient_lock_events
   1382  *
   1383  * Description: locks the client event structure
   1384  *
   1385  * Returns: void
   1386  ***********************************************************/
   1387 static void ilclient_lock_events(ILCLIENT_T *st)
   1388 {
   1389    vcos_semaphore_wait(&st->event_sema);
   1390 }
   1391 
   1392 /***********************************************************
   1393  * Name: ilclient_unlock_events
   1394  *
   1395  * Description: unlocks the client event structure
   1396  *
   1397  * Returns: void
   1398  ***********************************************************/
   1399 static void ilclient_unlock_events(ILCLIENT_T *st)
   1400 {
   1401    vcos_semaphore_post(&st->event_sema);
   1402 }
   1403 
   1404 /***********************************************************
   1405  * Name: ilclient_event_handler
   1406  *
   1407  * Description: event handler passed to core to use as component
   1408  * callback
   1409  *
   1410  * Returns: success
   1411  ***********************************************************/
   1412 static OMX_ERRORTYPE ilclient_event_handler(OMX_IN OMX_HANDLETYPE hComponent,
   1413                                             OMX_IN OMX_PTR pAppData,
   1414                                             OMX_IN OMX_EVENTTYPE eEvent,
   1415                                             OMX_IN OMX_U32 nData1,
   1416                                             OMX_IN OMX_U32 nData2,
   1417                                             OMX_IN OMX_PTR pEventData)
   1418 {
   1419    COMPONENT_T *st = (COMPONENT_T *) pAppData;
   1420    ILEVENT_T *event;
   1421    OMX_ERRORTYPE error = OMX_ErrorNone;
   1422 
   1423    ilclient_lock_events(st->client);
   1424 
   1425    // go through the events on this component and remove any duplicates in the
   1426    // existing list, since the client probably doesn't need them.  it's better
   1427    // than asserting when we run out.
   1428    event = st->list;
   1429    while(event != NULL)
   1430    {
   1431       ILEVENT_T **list = &(event->next);
   1432       while(*list != NULL)
   1433       {
   1434          if((*list)->eEvent == event->eEvent &&
   1435             (*list)->nData1 == event->nData1 &&
   1436             (*list)->nData2 == event->nData2)
   1437          {
   1438             // remove this duplicate
   1439             ILEVENT_T *rem = *list;
   1440             ilclient_debug_output("%s: removing %d/%d/%d", st->name, event->eEvent, event->nData1, event->nData2);            
   1441             *list = rem->next;
   1442             rem->eEvent = -1;
   1443             rem->next = st->client->event_list;
   1444             st->client->event_list = rem;
   1445          }
   1446          else
   1447             list = &((*list)->next);
   1448       }
   1449 
   1450       event = event->next;
   1451    }
   1452 
   1453    vc_assert(st->client->event_list);
   1454    event = st->client->event_list;
   1455 
   1456    switch (eEvent) {
   1457    case OMX_EventCmdComplete:
   1458       switch (nData1) {
   1459       case OMX_CommandStateSet:
   1460          ilclient_debug_output("%s: callback state changed (%s)", st->name, states[nData2]);
   1461          vcos_event_flags_set(&st->event, ILCLIENT_STATE_CHANGED, VCOS_OR);
   1462          break;
   1463       case OMX_CommandPortDisable:
   1464          ilclient_debug_output("%s: callback port disable %d", st->name, nData2);
   1465          vcos_event_flags_set(&st->event, ILCLIENT_PORT_DISABLED, VCOS_OR);
   1466          break;
   1467       case OMX_CommandPortEnable:
   1468          ilclient_debug_output("%s: callback port enable %d", st->name, nData2);
   1469          vcos_event_flags_set(&st->event, ILCLIENT_PORT_ENABLED, VCOS_OR);
   1470          break;
   1471       case OMX_CommandFlush:
   1472          ilclient_debug_output("%s: callback port flush %d", st->name, nData2);
   1473          vcos_event_flags_set(&st->event, ILCLIENT_PORT_FLUSH, VCOS_OR);
   1474          break;
   1475       case OMX_CommandMarkBuffer:
   1476          ilclient_debug_output("%s: callback mark buffer %d", st->name, nData2);
   1477          vcos_event_flags_set(&st->event, ILCLIENT_MARKED_BUFFER, VCOS_OR);
   1478          break;
   1479       default:
   1480          vc_assert(0);
   1481       }
   1482       break;
   1483    case OMX_EventError:
   1484       {
   1485          // check if this component failed a command, and we have to notify another command
   1486          // of this failure
   1487          if(nData2 == 1 && st->related != NULL)
   1488             vcos_event_flags_set(&st->related->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
   1489 
   1490          error = nData1;
   1491          switch (error) {
   1492          case OMX_ErrorPortUnpopulated:
   1493             if (st->error_mask & ILCLIENT_ERROR_UNPOPULATED)
   1494             {
   1495                ilclient_debug_output("%s: ignore error: port unpopulated (%d)", st->name, nData2);
   1496                event = NULL;
   1497                break;
   1498             }
   1499             ilclient_debug_output("%s: port unpopulated %x (%d)", st->name, error, nData2);
   1500             vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
   1501             break;
   1502          case OMX_ErrorSameState:
   1503             if (st->error_mask & ILCLIENT_ERROR_SAMESTATE)
   1504             {
   1505                ilclient_debug_output("%s: ignore error: same state (%d)", st->name, nData2);
   1506                event = NULL;
   1507                break;
   1508             }
   1509             ilclient_debug_output("%s: same state %x (%d)", st->name, error, nData2);
   1510             vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
   1511             break;
   1512          case OMX_ErrorBadParameter:
   1513             if (st->error_mask & ILCLIENT_ERROR_BADPARAMETER)
   1514             {
   1515                ilclient_debug_output("%s: ignore error: bad parameter (%d)", st->name, nData2);
   1516                event = NULL;
   1517                break;
   1518             }
   1519             ilclient_debug_output("%s: bad parameter %x (%d)", st->name, error, nData2);
   1520             vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
   1521             break;
   1522          case OMX_ErrorIncorrectStateTransition:
   1523             ilclient_debug_output("%s: incorrect state transition %x (%d)", st->name, error, nData2);
   1524             vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
   1525             break;
   1526          case OMX_ErrorBadPortIndex:
   1527             ilclient_debug_output("%s: bad port index %x (%d)", st->name, error, nData2);
   1528             vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
   1529             break;
   1530          case OMX_ErrorStreamCorrupt:
   1531             ilclient_debug_output("%s: stream corrupt %x (%d)", st->name, error, nData2);
   1532             vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
   1533             break;
   1534          case OMX_ErrorInsufficientResources:
   1535             ilclient_debug_output("%s: insufficient resources %x (%d)", st->name, error, nData2);
   1536             vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
   1537             break;
   1538          case OMX_ErrorUnsupportedSetting:
   1539             ilclient_debug_output("%s: unsupported setting %x (%d)", st->name, error, nData2);
   1540             vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
   1541             break;
   1542          case OMX_ErrorOverflow:
   1543             ilclient_debug_output("%s: overflow %x (%d)", st->name, error, nData2);
   1544             vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
   1545             break;
   1546          case OMX_ErrorDiskFull:
   1547             ilclient_debug_output("%s: disk full %x (%d)", st->name, error, nData2);
   1548             //we do not set the error
   1549             break;
   1550          case OMX_ErrorMaxFileSize:
   1551             ilclient_debug_output("%s: max file size %x (%d)", st->name, error, nData2);
   1552             //we do not set the error
   1553             break;
   1554          case OMX_ErrorDrmUnauthorised:
   1555             ilclient_debug_output("%s: drm file is unauthorised %x (%d)", st->name, error, nData2);
   1556             vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
   1557             break;
   1558          case OMX_ErrorDrmExpired:
   1559             ilclient_debug_output("%s: drm file has expired %x (%d)", st->name, error, nData2);
   1560             vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
   1561             break;
   1562          case OMX_ErrorDrmGeneral:
   1563             ilclient_debug_output("%s: drm library error %x (%d)", st->name, error, nData2);
   1564             vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
   1565             break;
   1566          default:
   1567             vc_assert(0);
   1568             ilclient_debug_output("%s: unexpected error %x (%d)", st->name, error, nData2);
   1569             vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
   1570             break;
   1571          }
   1572       }
   1573       break;
   1574    case OMX_EventBufferFlag:
   1575       ilclient_debug_output("%s: buffer flag %d/%x", st->name, nData1, nData2);
   1576       if (nData2 & OMX_BUFFERFLAG_EOS)
   1577       {
   1578          vcos_event_flags_set(&st->event, ILCLIENT_BUFFER_FLAG_EOS, VCOS_OR);
   1579          nData2 = OMX_BUFFERFLAG_EOS;
   1580       }
   1581       else
   1582          vc_assert(0);
   1583       break;
   1584    case OMX_EventPortSettingsChanged:
   1585       ilclient_debug_output("%s: port settings changed %d", st->name, nData1);
   1586       vcos_event_flags_set(&st->event, ILCLIENT_PARAMETER_CHANGED, VCOS_OR);
   1587       break;
   1588    case OMX_EventMark:
   1589       ilclient_debug_output("%s: buffer mark %p", st->name, pEventData);
   1590       vcos_event_flags_set(&st->event, ILCLIENT_BUFFER_MARK, VCOS_OR);
   1591       break;
   1592    case OMX_EventParamOrConfigChanged:
   1593       ilclient_debug_output("%s: param/config 0x%X on port %d changed", st->name, nData2, nData1);
   1594       vcos_event_flags_set(&st->event, ILCLIENT_CONFIG_CHANGED, VCOS_OR);
   1595       break;
   1596    default:
   1597       vc_assert(0);
   1598       break;
   1599    }
   1600 
   1601    if (event)
   1602    {
   1603       // fill in details
   1604       event->eEvent = eEvent;
   1605       event->nData1 = nData1;
   1606       event->nData2 = nData2;
   1607       event->pEventData = pEventData;
   1608 
   1609       // remove from top of spare list
   1610       st->client->event_list = st->client->event_list->next;
   1611 
   1612       // put at head of component event queue
   1613       event->next = st->list;
   1614       st->list = event;
   1615    }
   1616    ilclient_unlock_events(st->client);
   1617 
   1618    // now call any callbacks without the event lock so the client can 
   1619    // remove the event in context
   1620    switch(eEvent) {
   1621    case OMX_EventError:
   1622       if(event && st->client->error_callback)
   1623          st->client->error_callback(st->client->error_callback_data, st, error);
   1624       break;
   1625    case OMX_EventBufferFlag:
   1626       if ((nData2 & OMX_BUFFERFLAG_EOS) && st->client->eos_callback)
   1627          st->client->eos_callback(st->client->eos_callback_data, st, nData1);
   1628       break;
   1629    case OMX_EventPortSettingsChanged:
   1630       if (st->client->port_settings_callback)
   1631          st->client->port_settings_callback(st->client->port_settings_callback_data, st, nData1);
   1632       break;
   1633    case OMX_EventParamOrConfigChanged:
   1634       if (st->client->configchanged_callback)
   1635          st->client->configchanged_callback(st->client->configchanged_callback_data, st, nData2);
   1636       break;
   1637    default:
   1638       // ignore
   1639       break;
   1640    }
   1641 
   1642    return OMX_ErrorNone;
   1643 }
   1644 
   1645 /***********************************************************
   1646  * Name: ilclient_empty_buffer_done
   1647  *
   1648  * Description: passed to core to use as component callback, puts
   1649  * buffer on list
   1650  *
   1651  * Returns:
   1652  ***********************************************************/
   1653 static OMX_ERRORTYPE ilclient_empty_buffer_done(OMX_IN OMX_HANDLETYPE hComponent,
   1654       OMX_IN OMX_PTR pAppData,
   1655       OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
   1656 {
   1657    COMPONENT_T *st = (COMPONENT_T *) pAppData;
   1658    OMX_BUFFERHEADERTYPE *list;
   1659 
   1660    ilclient_debug_output("%s: empty buffer done %p", st->name, pBuffer);
   1661 
   1662    vcos_semaphore_wait(&st->sema);
   1663    // insert at end of the list, so we process buffers in
   1664    // the same order
   1665    list = st->in_list;
   1666    while(list && list->pAppPrivate)
   1667       list = list->pAppPrivate;
   1668 
   1669    if(!list)
   1670       st->in_list = pBuffer;
   1671    else
   1672       list->pAppPrivate = pBuffer;
   1673 
   1674    pBuffer->pAppPrivate = NULL;
   1675    vcos_semaphore_post(&st->sema);
   1676 
   1677    vcos_event_flags_set(&st->event, ILCLIENT_EMPTY_BUFFER_DONE, VCOS_OR);
   1678 
   1679    if (st->client->empty_buffer_done_callback)
   1680       st->client->empty_buffer_done_callback(st->client->empty_buffer_done_callback_data, st);
   1681 
   1682    return OMX_ErrorNone;
   1683 }
   1684 
   1685 /***********************************************************
   1686  * Name: ilclient_empty_buffer_done_error
   1687  *
   1688  * Description: passed to core to use as component callback, asserts
   1689  * on use as client not expecting component to use this callback.
   1690  *
   1691  * Returns:
   1692  ***********************************************************/
   1693 static OMX_ERRORTYPE ilclient_empty_buffer_done_error(OMX_IN OMX_HANDLETYPE hComponent,
   1694       OMX_IN OMX_PTR pAppData,
   1695       OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
   1696 {
   1697    vc_assert(0);
   1698    return OMX_ErrorNone;
   1699 }
   1700 
   1701 /***********************************************************
   1702  * Name: ilclient_fill_buffer_done
   1703  *
   1704  * Description: passed to core to use as component callback, puts
   1705  * buffer on list
   1706  *
   1707  * Returns:
   1708  ***********************************************************/
   1709 static OMX_ERRORTYPE ilclient_fill_buffer_done(OMX_OUT OMX_HANDLETYPE hComponent,
   1710       OMX_OUT OMX_PTR pAppData,
   1711       OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer)
   1712 {
   1713    COMPONENT_T *st = (COMPONENT_T *) pAppData;
   1714    OMX_BUFFERHEADERTYPE *list;
   1715 
   1716    ilclient_debug_output("%s: fill buffer done %p", st->name, pBuffer);
   1717 
   1718    vcos_semaphore_wait(&st->sema);
   1719    // insert at end of the list, so we process buffers in
   1720    // the correct order
   1721    list = st->out_list;
   1722    while(list && list->pAppPrivate)
   1723       list = list->pAppPrivate;
   1724 
   1725    if(!list)
   1726       st->out_list = pBuffer;
   1727    else
   1728       list->pAppPrivate = pBuffer;
   1729       
   1730    pBuffer->pAppPrivate = NULL;
   1731    vcos_semaphore_post(&st->sema);
   1732 
   1733    vcos_event_flags_set(&st->event, ILCLIENT_FILL_BUFFER_DONE, VCOS_OR);
   1734 
   1735    if (st->client->fill_buffer_done_callback)
   1736       st->client->fill_buffer_done_callback(st->client->fill_buffer_done_callback_data, st);
   1737 
   1738    return OMX_ErrorNone;
   1739 }
   1740 
   1741 /***********************************************************
   1742  * Name: ilclient_fill_buffer_done_error
   1743  *
   1744  * Description: passed to core to use as component callback, asserts
   1745  * on use as client not expecting component to use this callback.
   1746  *
   1747  * Returns:
   1748  ***********************************************************/
   1749 static OMX_ERRORTYPE ilclient_fill_buffer_done_error(OMX_OUT OMX_HANDLETYPE hComponent,
   1750       OMX_OUT OMX_PTR pAppData,
   1751       OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer)
   1752 {
   1753    vc_assert(0);
   1754    return OMX_ErrorNone;
   1755 }
   1756 
   1757 
   1758 
   1759 OMX_HANDLETYPE ilclient_get_handle(COMPONENT_T *comp)
   1760 {
   1761    vcos_assert(comp);
   1762    return comp->comp;
   1763 }
   1764 
   1765 
   1766 static struct {
   1767    OMX_PORTDOMAINTYPE dom;
   1768    int param;
   1769 } port_types[] = {
   1770    { OMX_PortDomainVideo, OMX_IndexParamVideoInit },
   1771    { OMX_PortDomainAudio, OMX_IndexParamAudioInit },
   1772    { OMX_PortDomainImage, OMX_IndexParamImageInit },
   1773    { OMX_PortDomainOther, OMX_IndexParamOtherInit },
   1774 };
   1775 
   1776 int ilclient_get_port_index(COMPONENT_T *comp, OMX_DIRTYPE dir, OMX_PORTDOMAINTYPE type, int index)
   1777 {
   1778    uint32_t i;
   1779    // for each possible port type...
   1780    for (i=0; i<sizeof(port_types)/sizeof(port_types[0]); i++)
   1781    {
   1782       if ((port_types[i].dom == type) || (type == (OMX_PORTDOMAINTYPE) -1))
   1783       {
   1784          OMX_PORT_PARAM_TYPE param;
   1785          OMX_ERRORTYPE error;
   1786          uint32_t j;
   1787 
   1788          param.nSize = sizeof(param);
   1789          param.nVersion.nVersion = OMX_VERSION;
   1790          error = OMX_GetParameter(ILC_GET_HANDLE(comp), port_types[i].param, &param);
   1791          assert(error == OMX_ErrorNone);
   1792 
   1793          // for each port of this type...
   1794          for (j=0; j<param.nPorts; j++)
   1795          {
   1796             int port = param.nStartPortNumber+j;
   1797 
   1798             OMX_PARAM_PORTDEFINITIONTYPE portdef;
   1799             portdef.nSize = sizeof(portdef);
   1800             portdef.nVersion.nVersion = OMX_VERSION;
   1801             portdef.nPortIndex = port;
   1802 
   1803             error = OMX_GetParameter(ILC_GET_HANDLE(comp), OMX_IndexParamPortDefinition, &portdef);
   1804             assert(error == OMX_ErrorNone);
   1805 
   1806             if (portdef.eDir == dir)
   1807             {
   1808                if (index-- == 0)
   1809                   return port;
   1810             }
   1811          }
   1812       }
   1813    }
   1814    return -1;
   1815 }
   1816 
   1817 int ilclient_suggest_bufsize(COMPONENT_T *comp, OMX_U32 nBufSizeHint)
   1818 {
   1819    OMX_PARAM_BRCMOUTPUTBUFFERSIZETYPE param;
   1820    OMX_ERRORTYPE error;
   1821 
   1822    param.nSize = sizeof(param);
   1823    param.nVersion.nVersion = OMX_VERSION;
   1824    param.nBufferSize = nBufSizeHint;
   1825    error = OMX_SetParameter(ILC_GET_HANDLE(comp), OMX_IndexParamBrcmOutputBufferSize,
   1826                             &param);
   1827    assert(error == OMX_ErrorNone);
   1828 
   1829    return (error == OMX_ErrorNone) ? 0 : -1;
   1830 }
   1831 
   1832 unsigned int ilclient_stack_size(void)
   1833 {
   1834    return ILCLIENT_THREAD_DEFAULT_STACK_SIZE;
   1835 }
   1836