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  ***********************************************************/
ilclient_init()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  ***********************************************************/
ilclient_destroy(ILCLIENT_T * st)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  ***********************************************************/
ilclient_set_port_settings_callback(ILCLIENT_T * st,ILCLIENT_CALLBACK_T func,void * userdata)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  ***********************************************************/
ilclient_set_eos_callback(ILCLIENT_T * st,ILCLIENT_CALLBACK_T func,void * userdata)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  ***********************************************************/
ilclient_set_error_callback(ILCLIENT_T * st,ILCLIENT_CALLBACK_T func,void * userdata)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  ***********************************************************/
ilclient_set_fill_buffer_done_callback(ILCLIENT_T * st,ILCLIENT_BUFFER_CALLBACK_T func,void * userdata)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  ***********************************************************/
ilclient_set_empty_buffer_done_callback(ILCLIENT_T * st,ILCLIENT_BUFFER_CALLBACK_T func,void * userdata)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  ***********************************************************/
ilclient_set_configchanged_callback(ILCLIENT_T * st,ILCLIENT_CALLBACK_T func,void * userdata)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  ***********************************************************/
ilclient_create_component(ILCLIENT_T * client,COMPONENT_T ** comp,char * name,ILCLIENT_CREATE_FLAGS_T flags)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  ***********************************************************/
ilclient_remove_event(COMPONENT_T * st,OMX_EVENTTYPE eEvent,OMX_U32 nData1,int ignore1,OMX_IN OMX_U32 nData2,int ignore2)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  ***********************************************************/
ilclient_state_transition(COMPONENT_T * list[],OMX_STATETYPE state)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  ***********************************************************/
ilclient_teardown_tunnels(TUNNEL_T * tunnel)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  ***********************************************************/
ilclient_disable_tunnel(TUNNEL_T * tunnel)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  ***********************************************************/
ilclient_enable_tunnel(TUNNEL_T * tunnel)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  ***********************************************************/
ilclient_flush_tunnels(TUNNEL_T * tunnel,int max)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  ***********************************************************/
ilclient_return_events(COMPONENT_T * comp)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  ***********************************************************/
ilclient_cleanup_components(COMPONENT_T * list[])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  ***********************************************************/
ilclient_change_component_state(COMPONENT_T * comp,OMX_STATETYPE state)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  ***********************************************************/
ilclient_disable_port(COMPONENT_T * comp,int portIndex)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  ***********************************************************/
ilclient_enable_port(COMPONENT_T * comp,int portIndex)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  ***********************************************************/
ilclient_enable_port_buffers(COMPONENT_T * comp,int portIndex,ILCLIENT_MALLOC_T ilclient_malloc,ILCLIENT_FREE_T ilclient_free,void * private)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  ***********************************************************/
ilclient_disable_port_buffers(COMPONENT_T * comp,int portIndex,OMX_BUFFERHEADERTYPE * bufferList,ILCLIENT_FREE_T ilclient_free,void * private)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  ***********************************************************/
ilclient_setup_tunnel(TUNNEL_T * tunnel,unsigned int portStream,int timeout)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  ***********************************************************/
ilclient_wait_for_event(COMPONENT_T * comp,OMX_EVENTTYPE event,OMX_U32 nData1,int ignore1,OMX_IN OMX_U32 nData2,int ignore2,int event_flag,int suspend)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  ***********************************************************/
ilclient_wait_for_command_complete_dual(COMPONENT_T * comp,OMX_COMMANDTYPE command,OMX_U32 nData2,COMPONENT_T * other)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  ***********************************************************/
ilclient_wait_for_command_complete(COMPONENT_T * comp,OMX_COMMANDTYPE command,OMX_U32 nData2)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  ***********************************************************/
ilclient_get_output_buffer(COMPONENT_T * comp,int portIndex,int block)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  ***********************************************************/
ilclient_get_input_buffer(COMPONENT_T * comp,int portIndex,int block)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  ***********************************************************/
ilclient_debug_output(char * format,...)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  ***********************************************************/
ilclient_lock_events(ILCLIENT_T * st)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  ***********************************************************/
ilclient_unlock_events(ILCLIENT_T * st)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  ***********************************************************/
ilclient_event_handler(OMX_IN OMX_HANDLETYPE hComponent,OMX_IN OMX_PTR pAppData,OMX_IN OMX_EVENTTYPE eEvent,OMX_IN OMX_U32 nData1,OMX_IN OMX_U32 nData2,OMX_IN OMX_PTR pEventData)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  ***********************************************************/
ilclient_empty_buffer_done(OMX_IN OMX_HANDLETYPE hComponent,OMX_IN OMX_PTR pAppData,OMX_IN OMX_BUFFERHEADERTYPE * pBuffer)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  ***********************************************************/
ilclient_empty_buffer_done_error(OMX_IN OMX_HANDLETYPE hComponent,OMX_IN OMX_PTR pAppData,OMX_IN OMX_BUFFERHEADERTYPE * pBuffer)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  ***********************************************************/
ilclient_fill_buffer_done(OMX_OUT OMX_HANDLETYPE hComponent,OMX_OUT OMX_PTR pAppData,OMX_OUT OMX_BUFFERHEADERTYPE * pBuffer)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  ***********************************************************/
ilclient_fill_buffer_done_error(OMX_OUT OMX_HANDLETYPE hComponent,OMX_OUT OMX_PTR pAppData,OMX_OUT OMX_BUFFERHEADERTYPE * pBuffer)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 
ilclient_get_handle(COMPONENT_T * comp)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 
ilclient_get_port_index(COMPONENT_T * comp,OMX_DIRTYPE dir,OMX_PORTDOMAINTYPE type,int index)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 
ilclient_suggest_bufsize(COMPONENT_T * comp,OMX_U32 nBufSizeHint)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 
ilclient_stack_size(void)1832 unsigned int ilclient_stack_size(void)
1833 {
1834    return ILCLIENT_THREAD_DEFAULT_STACK_SIZE;
1835 }
1836 
1837