|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836 |
- /*
- Copyright (c) 2012, Broadcom Europe Ltd
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- * Neither the name of the copyright holder nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
- /*
- * \file
- *
- * \brief This API defines helper functions for writing IL clients.
- *
- * This file defines an IL client side library. This is useful when
- * writing IL clients, since there tends to be much repeated and
- * common code across both single and multiple clients. This library
- * seeks to remove that common code and abstract some of the
- * interactions with components. There is a wrapper around a
- * component and tunnel, and some operations can be done on lists of
- * these. The callbacks from components are handled, and specific
- * events can be checked or waited for.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <string.h>
- #include <ctype.h>
- #include <assert.h>
-
- #include "interface/vcos/vcos.h"
- #include "interface/vcos/vcos_logging.h"
- #include "interface/vmcs_host/vchost.h"
-
- #include "IL/OMX_Broadcom.h"
- #include "ilclient.h"
-
- #define VCOS_LOG_CATEGORY (&ilclient_log_category)
-
- #ifndef ILCLIENT_THREAD_DEFAULT_STACK_SIZE
- #define ILCLIENT_THREAD_DEFAULT_STACK_SIZE (6<<10)
- #endif
-
- static VCOS_LOG_CAT_T ilclient_log_category;
-
- /******************************************************************************
- Static data and types used only in this file.
- ******************************************************************************/
-
- struct _ILEVENT_T {
- OMX_EVENTTYPE eEvent;
- OMX_U32 nData1;
- OMX_U32 nData2;
- OMX_PTR pEventData;
- struct _ILEVENT_T *next;
- };
-
- #define NUM_EVENTS 100
- struct _ILCLIENT_T {
- ILEVENT_T *event_list;
- VCOS_SEMAPHORE_T event_sema;
- ILEVENT_T event_rep[NUM_EVENTS];
-
- ILCLIENT_CALLBACK_T port_settings_callback;
- void *port_settings_callback_data;
- ILCLIENT_CALLBACK_T eos_callback;
- void *eos_callback_data;
- ILCLIENT_CALLBACK_T error_callback;
- void *error_callback_data;
- ILCLIENT_BUFFER_CALLBACK_T fill_buffer_done_callback;
- void *fill_buffer_done_callback_data;
- ILCLIENT_BUFFER_CALLBACK_T empty_buffer_done_callback;
- void *empty_buffer_done_callback_data;
- ILCLIENT_CALLBACK_T configchanged_callback;
- void *configchanged_callback_data;
- };
-
- struct _COMPONENT_T {
- OMX_HANDLETYPE comp;
- ILCLIENT_CREATE_FLAGS_T flags;
- VCOS_SEMAPHORE_T sema;
- VCOS_EVENT_FLAGS_T event;
- struct _COMPONENT_T *related;
- OMX_BUFFERHEADERTYPE *out_list;
- OMX_BUFFERHEADERTYPE *in_list;
- char name[32];
- char bufname[32];
- unsigned int error_mask;
- unsigned int private;
- ILEVENT_T *list;
- ILCLIENT_T *client;
- };
-
- #define random_wait()
- static char *states[] = {"Invalid", "Loaded", "Idle", "Executing", "Pause", "WaitingForResources"};
-
- typedef enum {
- ILCLIENT_ERROR_UNPOPULATED = 0x1,
- ILCLIENT_ERROR_SAMESTATE = 0x2,
- ILCLIENT_ERROR_BADPARAMETER = 0x4
- } ILERROR_MASK_T;
-
- /******************************************************************************
- Static functions.
- ******************************************************************************/
-
- static OMX_ERRORTYPE ilclient_empty_buffer_done(OMX_IN OMX_HANDLETYPE hComponent,
- OMX_IN OMX_PTR pAppData,
- OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
- static OMX_ERRORTYPE ilclient_empty_buffer_done_error(OMX_IN OMX_HANDLETYPE hComponent,
- OMX_IN OMX_PTR pAppData,
- OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
- static OMX_ERRORTYPE ilclient_fill_buffer_done(OMX_OUT OMX_HANDLETYPE hComponent,
- OMX_OUT OMX_PTR pAppData,
- OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer);
- static OMX_ERRORTYPE ilclient_fill_buffer_done_error(OMX_OUT OMX_HANDLETYPE hComponent,
- OMX_OUT OMX_PTR pAppData,
- OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer);
- static OMX_ERRORTYPE 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);
- static void ilclient_lock_events(ILCLIENT_T *st);
- static void ilclient_unlock_events(ILCLIENT_T *st);
-
- /******************************************************************************
- Global functions
- ******************************************************************************/
-
- /***********************************************************
- * Name: ilclient_init
- *
- * Description: Creates ilclient pointer
- *
- * Returns: pointer to client structure
- ***********************************************************/
- ILCLIENT_T *ilclient_init()
- {
- ILCLIENT_T *st = vcos_malloc(sizeof(ILCLIENT_T), "ilclient");
- int i;
-
- if (!st)
- return NULL;
-
- vcos_log_set_level(VCOS_LOG_CATEGORY, VCOS_LOG_WARN);
- vcos_log_register("ilclient", VCOS_LOG_CATEGORY);
-
- memset(st, 0, sizeof(ILCLIENT_T));
-
- i = vcos_semaphore_create(&st->event_sema, "il:event", 1);
- vc_assert(i == VCOS_SUCCESS);
-
- ilclient_lock_events(st);
- st->event_list = NULL;
- for (i=0; i<NUM_EVENTS; i++)
- {
- st->event_rep[i].eEvent = -1; // mark as unused
- st->event_rep[i].next = st->event_list;
- st->event_list = st->event_rep+i;
- }
- ilclient_unlock_events(st);
- return st;
- }
-
- /***********************************************************
- * Name: ilclient_destroy
- *
- * Description: frees client state
- *
- * Returns: void
- ***********************************************************/
- void ilclient_destroy(ILCLIENT_T *st)
- {
- vcos_semaphore_delete(&st->event_sema);
- vcos_free(st);
- vcos_log_unregister(VCOS_LOG_CATEGORY);
- }
-
- /***********************************************************
- * Name: ilclient_set_port_settings_callback
- *
- * Description: sets the callback used when receiving port settings
- * changed messages. The data field in the callback function will be
- * the port index reporting the message.
- *
- * Returns: void
- ***********************************************************/
- void ilclient_set_port_settings_callback(ILCLIENT_T *st, ILCLIENT_CALLBACK_T func, void *userdata)
- {
- st->port_settings_callback = func;
- st->port_settings_callback_data = userdata;
- }
-
- /***********************************************************
- * Name: ilclient_set_eos_callback
- *
- * Description: sets the callback used when receiving eos flags. The
- * data parameter in the callback function will be the port index
- * reporting an eos flag.
- *
- * Returns: void
- ***********************************************************/
- void ilclient_set_eos_callback(ILCLIENT_T *st, ILCLIENT_CALLBACK_T func, void *userdata)
- {
- st->eos_callback = func;
- st->eos_callback_data = userdata;
- }
-
- /***********************************************************
- * Name: ilclient_set_error_callback
- *
- * Description: sets the callback used when receiving error events.
- * The data parameter in the callback function will be the error code
- * being reported.
- *
- * Returns: void
- ***********************************************************/
- void ilclient_set_error_callback(ILCLIENT_T *st, ILCLIENT_CALLBACK_T func, void *userdata)
- {
- st->error_callback = func;
- st->error_callback_data = userdata;
- }
-
- /***********************************************************
- * Name: ilclient_set_fill_buffer_done_callback
- *
- * Description: sets the callback used when receiving
- * fill_buffer_done event
- *
- * Returns: void
- ***********************************************************/
- void ilclient_set_fill_buffer_done_callback(ILCLIENT_T *st, ILCLIENT_BUFFER_CALLBACK_T func, void *userdata)
- {
- st->fill_buffer_done_callback = func;
- st->fill_buffer_done_callback_data = userdata;
- }
-
- /***********************************************************
- * Name: ilclient_set_empty_buffer_done_callback
- *
- * Description: sets the callback used when receiving
- * empty_buffer_done event
- *
- * Returns: void
- ***********************************************************/
- void ilclient_set_empty_buffer_done_callback(ILCLIENT_T *st, ILCLIENT_BUFFER_CALLBACK_T func, void *userdata)
- {
- st->empty_buffer_done_callback = func;
- st->empty_buffer_done_callback_data = userdata;
- }
-
- /***********************************************************
- * Name: ilclient_set_configchanged_callback
- *
- * Description: sets the callback used when a config changed
- * event is received
- *
- * Returns: void
- ***********************************************************/
- void ilclient_set_configchanged_callback(ILCLIENT_T *st, ILCLIENT_CALLBACK_T func, void *userdata)
- {
- st->configchanged_callback = func;
- st->configchanged_callback_data = userdata;
- }
-
- /***********************************************************
- * Name: ilclient_create_component
- *
- * Description: initialises a component state structure and creates
- * the IL component.
- *
- * Returns: 0 on success, -1 on failure
- ***********************************************************/
- int ilclient_create_component(ILCLIENT_T *client, COMPONENT_T **comp, char *name,
- ILCLIENT_CREATE_FLAGS_T flags)
- {
- OMX_CALLBACKTYPE callbacks;
- OMX_ERRORTYPE error;
- char component_name[128];
- int32_t status;
-
- *comp = vcos_malloc(sizeof(COMPONENT_T), "il:comp");
- if(!*comp)
- return -1;
-
- memset(*comp, 0, sizeof(COMPONENT_T));
-
- #define COMP_PREFIX "OMX.broadcom."
-
- status = vcos_event_flags_create(&(*comp)->event,"il:comp");
- vc_assert(status == VCOS_SUCCESS);
- status = vcos_semaphore_create(&(*comp)->sema, "il:comp", 1);
- vc_assert(status == VCOS_SUCCESS);
- (*comp)->client = client;
-
- vcos_snprintf((*comp)->name, sizeof((*comp)->name), "cl:%s", name);
- vcos_snprintf((*comp)->bufname, sizeof((*comp)->bufname), "cl:%s buffer", name);
- vcos_snprintf(component_name, sizeof(component_name), "%s%s", COMP_PREFIX, name);
-
- (*comp)->flags = flags;
-
- callbacks.EventHandler = ilclient_event_handler;
- callbacks.EmptyBufferDone = flags & ILCLIENT_ENABLE_INPUT_BUFFERS ? ilclient_empty_buffer_done : ilclient_empty_buffer_done_error;
- callbacks.FillBufferDone = flags & ILCLIENT_ENABLE_OUTPUT_BUFFERS ? ilclient_fill_buffer_done : ilclient_fill_buffer_done_error;
-
- error = OMX_GetHandle(&(*comp)->comp, component_name, *comp, &callbacks);
-
- if (error == OMX_ErrorNone)
- {
- OMX_UUIDTYPE uid;
- char name[128];
- OMX_VERSIONTYPE compVersion, specVersion;
-
- if(OMX_GetComponentVersion((*comp)->comp, name, &compVersion, &specVersion, &uid) == OMX_ErrorNone)
- {
- char *p = (char *) uid + strlen(COMP_PREFIX);
-
- vcos_snprintf((*comp)->name, sizeof((*comp)->name), "cl:%s", p);
- (*comp)->name[sizeof((*comp)->name)-1] = 0;
- vcos_snprintf((*comp)->bufname, sizeof((*comp)->bufname), "cl:%s buffer", p);
- (*comp)->bufname[sizeof((*comp)->bufname)-1] = 0;
- }
-
- if(flags & (ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_OUTPUT_ZERO_BUFFERS))
- {
- OMX_PORT_PARAM_TYPE ports;
- OMX_INDEXTYPE types[] = {OMX_IndexParamAudioInit, OMX_IndexParamVideoInit, OMX_IndexParamImageInit, OMX_IndexParamOtherInit};
- int i;
-
- ports.nSize = sizeof(OMX_PORT_PARAM_TYPE);
- ports.nVersion.nVersion = OMX_VERSION;
-
- for(i=0; i<4; i++)
- {
- OMX_ERRORTYPE error = OMX_GetParameter((*comp)->comp, types[i], &ports);
- if(error == OMX_ErrorNone)
- {
- uint32_t j;
- for(j=0; j<ports.nPorts; j++)
- {
- if(flags & ILCLIENT_DISABLE_ALL_PORTS)
- ilclient_disable_port(*comp, ports.nStartPortNumber+j);
-
- if(flags & ILCLIENT_OUTPUT_ZERO_BUFFERS)
- {
- OMX_PARAM_PORTDEFINITIONTYPE portdef;
- portdef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
- portdef.nVersion.nVersion = OMX_VERSION;
- portdef.nPortIndex = ports.nStartPortNumber+j;
- if(OMX_GetParameter((*comp)->comp, OMX_IndexParamPortDefinition, &portdef) == OMX_ErrorNone)
- {
- if(portdef.eDir == OMX_DirOutput && portdef.nBufferCountActual > 0)
- {
- portdef.nBufferCountActual = 0;
- OMX_SetParameter((*comp)->comp, OMX_IndexParamPortDefinition, &portdef);
- }
- }
- }
- }
- }
- }
- }
- return 0;
- }
- else
- {
- vcos_event_flags_delete(&(*comp)->event);
- vcos_semaphore_delete(&(*comp)->sema);
- vcos_free(*comp);
- *comp = NULL;
- return -1;
- }
- }
-
- /***********************************************************
- * Name: ilclient_remove_event
- *
- * Description: Removes an event from a component event list. ignore1
- * and ignore2 are flags indicating whether to not match on nData1 and
- * nData2 respectively.
- *
- * Returns: 0 if the event was removed. -1 if no matching event was
- * found.
- ***********************************************************/
- int ilclient_remove_event(COMPONENT_T *st, OMX_EVENTTYPE eEvent,
- OMX_U32 nData1, int ignore1, OMX_IN OMX_U32 nData2, int ignore2)
- {
- ILEVENT_T *cur, *prev;
- uint32_t set;
- ilclient_lock_events(st->client);
-
- cur = st->list;
- prev = NULL;
-
- while (cur && !(cur->eEvent == eEvent && (ignore1 || cur->nData1 == nData1) && (ignore2 || cur->nData2 == nData2)))
- {
- prev = cur;
- cur = cur->next;
- }
-
- if (cur == NULL)
- {
- ilclient_unlock_events(st->client);
- return -1;
- }
-
- if (prev == NULL)
- st->list = cur->next;
- else
- prev->next = cur->next;
-
- // add back into spare list
- cur->next = st->client->event_list;
- st->client->event_list = cur;
- cur->eEvent = -1; // mark as unused
-
- // if we're removing an OMX_EventError or OMX_EventParamOrConfigChanged event, then clear the error bit from the eventgroup,
- // since the user might have been notified through the error callback, and then
- // can't clear the event bit - this will then cause problems the next time they
- // wait for an error.
- if(eEvent == OMX_EventError)
- vcos_event_flags_get(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR_CONSUME, 0, &set);
- else if(eEvent == OMX_EventParamOrConfigChanged)
- vcos_event_flags_get(&st->event, ILCLIENT_CONFIG_CHANGED, VCOS_OR_CONSUME, 0, &set);
-
- ilclient_unlock_events(st->client);
- return 0;
- }
-
- /***********************************************************
- * Name: ilclient_state_transition
- *
- * Description: Transitions a null terminated list of IL components to
- * a given state. All components are told to transition in a random
- * order before any are checked for transition completion.
- *
- * Returns: void
- ***********************************************************/
- void ilclient_state_transition(COMPONENT_T *list[], OMX_STATETYPE state)
- {
- OMX_ERRORTYPE error;
- int i, num;
- uint32_t set;
-
- num=0;
- while (list[num])
- num++;
-
- // if we transition the supplier port first, it will call freebuffer on the non
- // supplier, which will correctly signal a port unpopulated error. We want to
- // ignore these errors.
- if (state == OMX_StateLoaded)
- for (i=0; i<num; i++)
- list[i]->error_mask |= ILCLIENT_ERROR_UNPOPULATED;
- for (i=0; i<num; i++)
- list[i]->private = ((rand() >> 13) & 0xff)+1;
-
- for (i=0; i<num; i++)
- {
- // transition the components in a random order
- int j, min = -1;
- for (j=0; j<num; j++)
- if (list[j]->private && (min == -1 || list[min]->private > list[j]->private))
- min = j;
-
- list[min]->private = 0;
-
- random_wait();
- //Clear error event for this component
- vcos_event_flags_get(&list[min]->event, ILCLIENT_EVENT_ERROR, VCOS_OR_CONSUME, 0, &set);
-
- error = OMX_SendCommand(list[min]->comp, OMX_CommandStateSet, state, NULL);
- vc_assert(error == OMX_ErrorNone);
- }
-
- random_wait();
-
- for (i=0; i<num; i++)
- if(ilclient_wait_for_command_complete(list[i], OMX_CommandStateSet, state) < 0)
- vc_assert(0);
-
- if (state == OMX_StateLoaded)
- for (i=0; i<num; i++)
- list[i]->error_mask &= ~ILCLIENT_ERROR_UNPOPULATED;
- }
-
- /***********************************************************
- * Name: ilclient_teardown_tunnels
- *
- * Description: tears down a null terminated list of tunnels.
- *
- * Returns: void
- ***********************************************************/
- void ilclient_teardown_tunnels(TUNNEL_T *tunnel)
- {
- int i;
- OMX_ERRORTYPE error;
-
- i=0;;
- while (tunnel[i].source)
- {
- error = OMX_SetupTunnel(tunnel[i].source->comp, tunnel[i].source_port, NULL, 0);
- vc_assert(error == OMX_ErrorNone);
-
- error = OMX_SetupTunnel(tunnel[i].sink->comp, tunnel[i].sink_port, NULL, 0);
- vc_assert(error == OMX_ErrorNone);
- i++;
- }
- }
-
- /***********************************************************
- * Name: ilclient_disable_tunnel
- *
- * Description: disables a tunnel by disabling the ports. Allows
- * ports to signal same state error if they were already disabled.
- *
- * Returns: void
- ***********************************************************/
- void ilclient_disable_tunnel(TUNNEL_T *tunnel)
- {
- OMX_ERRORTYPE error;
-
- if(tunnel->source == 0 || tunnel->sink == 0)
- return;
-
- tunnel->source->error_mask |= ILCLIENT_ERROR_UNPOPULATED;
- tunnel->sink->error_mask |= ILCLIENT_ERROR_UNPOPULATED;
-
- error = OMX_SendCommand(tunnel->source->comp, OMX_CommandPortDisable, tunnel->source_port, NULL);
- vc_assert(error == OMX_ErrorNone);
-
- error = OMX_SendCommand(tunnel->sink->comp, OMX_CommandPortDisable, tunnel->sink_port, NULL);
- vc_assert(error == OMX_ErrorNone);
-
- if(ilclient_wait_for_command_complete(tunnel->source, OMX_CommandPortDisable, tunnel->source_port) < 0)
- vc_assert(0);
-
- if(ilclient_wait_for_command_complete(tunnel->sink, OMX_CommandPortDisable, tunnel->sink_port) < 0)
- vc_assert(0);
-
- tunnel->source->error_mask &= ~ILCLIENT_ERROR_UNPOPULATED;
- tunnel->sink->error_mask &= ~ILCLIENT_ERROR_UNPOPULATED;
- }
-
- /***********************************************************
- * Name: ilclient_enable_tunnel
- *
- * Description: enables a tunnel by enabling the ports
- *
- * Returns: 0 on success, -1 on failure
- ***********************************************************/
- int ilclient_enable_tunnel(TUNNEL_T *tunnel)
- {
- OMX_STATETYPE state;
- OMX_ERRORTYPE error;
-
- ilclient_debug_output("ilclient: enable tunnel from %x/%d to %x/%d",
- tunnel->source, tunnel->source_port,
- tunnel->sink, tunnel->sink_port);
-
- error = OMX_SendCommand(tunnel->source->comp, OMX_CommandPortEnable, tunnel->source_port, NULL);
- vc_assert(error == OMX_ErrorNone);
-
- error = OMX_SendCommand(tunnel->sink->comp, OMX_CommandPortEnable, tunnel->sink_port, NULL);
- vc_assert(error == OMX_ErrorNone);
-
- // to complete, the sink component can't be in loaded state
- error = OMX_GetState(tunnel->sink->comp, &state);
- vc_assert(error == OMX_ErrorNone);
- if (state == OMX_StateLoaded)
- {
- int ret = 0;
-
- if(ilclient_wait_for_command_complete(tunnel->sink, OMX_CommandPortEnable, tunnel->sink_port) != 0 ||
- OMX_SendCommand(tunnel->sink->comp, OMX_CommandStateSet, OMX_StateIdle, NULL) != OMX_ErrorNone ||
- (ret = ilclient_wait_for_command_complete_dual(tunnel->sink, OMX_CommandStateSet, OMX_StateIdle, tunnel->source)) < 0)
- {
- if(ret == -2)
- {
- // the error was reported fom the source component: clear this error and disable the sink component
- ilclient_wait_for_command_complete(tunnel->source, OMX_CommandPortEnable, tunnel->source_port);
- ilclient_disable_port(tunnel->sink, tunnel->sink_port);
- }
-
- ilclient_debug_output("ilclient: could not change component state to IDLE");
- ilclient_disable_port(tunnel->source, tunnel->source_port);
- return -1;
- }
- }
- else
- {
- if (ilclient_wait_for_command_complete(tunnel->sink, OMX_CommandPortEnable, tunnel->sink_port) != 0)
- {
- ilclient_debug_output("ilclient: could not change sink port %d to enabled", tunnel->sink_port);
-
- //Oops failed to enable the sink port
- ilclient_disable_port(tunnel->source, tunnel->source_port);
- //Clean up the port enable event from the source port.
- ilclient_wait_for_event(tunnel->source, OMX_EventCmdComplete,
- OMX_CommandPortEnable, 0, tunnel->source_port, 0,
- ILCLIENT_PORT_ENABLED | ILCLIENT_EVENT_ERROR, VCOS_EVENT_FLAGS_SUSPEND);
- return -1;
- }
- }
-
- if(ilclient_wait_for_command_complete(tunnel->source, OMX_CommandPortEnable, tunnel->source_port) != 0)
- {
- ilclient_debug_output("ilclient: could not change source port %d to enabled", tunnel->source_port);
-
- //Failed to enable the source port
- ilclient_disable_port(tunnel->sink, tunnel->sink_port);
- return -1;
- }
-
- return 0;
- }
-
-
- /***********************************************************
- * Name: ilclient_flush_tunnels
- *
- * Description: flushes all ports used in a null terminated list of
- * tunnels. max specifies the maximum number of tunnels to flush from
- * the list, where max=0 means all tunnels.
- *
- * Returns: void
- ***********************************************************/
- void ilclient_flush_tunnels(TUNNEL_T *tunnel, int max)
- {
- OMX_ERRORTYPE error;
- int i;
-
- i=0;
- while (tunnel[i].source && (max == 0 || i < max))
- {
- error = OMX_SendCommand(tunnel[i].source->comp, OMX_CommandFlush, tunnel[i].source_port, NULL);
- vc_assert(error == OMX_ErrorNone);
-
- error = OMX_SendCommand(tunnel[i].sink->comp, OMX_CommandFlush, tunnel[i].sink_port, NULL);
- vc_assert(error == OMX_ErrorNone);
-
- ilclient_wait_for_event(tunnel[i].source, OMX_EventCmdComplete,
- OMX_CommandFlush, 0, tunnel[i].source_port, 0,
- ILCLIENT_PORT_FLUSH, VCOS_EVENT_FLAGS_SUSPEND);
- ilclient_wait_for_event(tunnel[i].sink, OMX_EventCmdComplete,
- OMX_CommandFlush, 0, tunnel[i].sink_port, 0,
- ILCLIENT_PORT_FLUSH, VCOS_EVENT_FLAGS_SUSPEND);
- i++;
- }
- }
-
-
- /***********************************************************
- * Name: ilclient_return_events
- *
- * Description: Returns all events from a component event list to the
- * list of unused event structures.
- *
- * Returns: void
- ***********************************************************/
- void ilclient_return_events(COMPONENT_T *comp)
- {
- ilclient_lock_events(comp->client);
- while (comp->list)
- {
- ILEVENT_T *next = comp->list->next;
- comp->list->next = comp->client->event_list;
- comp->client->event_list = comp->list;
- comp->list = next;
- }
- ilclient_unlock_events(comp->client);
- }
-
- /***********************************************************
- * Name: ilclient_cleanup_components
- *
- * Description: frees all components from a null terminated list and
- * deletes resources used in component state structure.
- *
- * Returns: void
- ***********************************************************/
- void ilclient_cleanup_components(COMPONENT_T *list[])
- {
- int i;
- OMX_ERRORTYPE error;
-
- i=0;
- while (list[i])
- {
- ilclient_return_events(list[i]);
- if (list[i]->comp)
- {
- error = OMX_FreeHandle(list[i]->comp);
-
- vc_assert(error == OMX_ErrorNone);
- }
- i++;
- }
-
- i=0;
- while (list[i])
- {
- vcos_event_flags_delete(&list[i]->event);
- vcos_semaphore_delete(&list[i]->sema);
- vcos_free(list[i]);
- list[i] = NULL;
- i++;
- }
- }
-
- /***********************************************************
- * Name: ilclient_change_component_state
- *
- * Description: changes the state of a single component. Note: this
- * may not be suitable if the component is tunnelled and requires
- * connected components to also change state.
- *
- * Returns: 0 on success, -1 on failure (note - trying to change to
- * the same state which causes a OMX_ErrorSameState is treated as
- * success)
- ***********************************************************/
- int ilclient_change_component_state(COMPONENT_T *comp, OMX_STATETYPE state)
- {
- OMX_ERRORTYPE error;
- error = OMX_SendCommand(comp->comp, OMX_CommandStateSet, state, NULL);
- vc_assert(error == OMX_ErrorNone);
- if(ilclient_wait_for_command_complete(comp, OMX_CommandStateSet, state) < 0)
- {
- ilclient_debug_output("ilclient: could not change component state to %d", state);
- ilclient_remove_event(comp, OMX_EventError, 0, 1, 0, 1);
- return -1;
- }
- return 0;
- }
-
- /***********************************************************
- * Name: ilclient_disable_port
- *
- * Description: disables a port on a given component.
- *
- * Returns: void
- ***********************************************************/
- void ilclient_disable_port(COMPONENT_T *comp, int portIndex)
- {
- OMX_ERRORTYPE error;
- error = OMX_SendCommand(comp->comp, OMX_CommandPortDisable, portIndex, NULL);
- vc_assert(error == OMX_ErrorNone);
- if(ilclient_wait_for_command_complete(comp, OMX_CommandPortDisable, portIndex) < 0)
- vc_assert(0);
- }
-
- /***********************************************************
- * Name: ilclient_enabled_port
- *
- * Description: enables a port on a given component.
- *
- * Returns: void
- ***********************************************************/
- void ilclient_enable_port(COMPONENT_T *comp, int portIndex)
- {
- OMX_ERRORTYPE error;
- error = OMX_SendCommand(comp->comp, OMX_CommandPortEnable, portIndex, NULL);
- vc_assert(error == OMX_ErrorNone);
- if(ilclient_wait_for_command_complete(comp, OMX_CommandPortEnable, portIndex) < 0)
- vc_assert(0);
- }
-
-
- /***********************************************************
- * Name: ilclient_enable_port_buffers
- *
- * Description: enables a port on a given component which requires
- * buffers to be supplied by the client.
- *
- * Returns: void
- ***********************************************************/
- int ilclient_enable_port_buffers(COMPONENT_T *comp, int portIndex,
- ILCLIENT_MALLOC_T ilclient_malloc,
- ILCLIENT_FREE_T ilclient_free,
- void *private)
- {
- OMX_ERRORTYPE error;
- OMX_PARAM_PORTDEFINITIONTYPE portdef;
- OMX_BUFFERHEADERTYPE *list = NULL, **end = &list;
- OMX_STATETYPE state;
- int i;
-
- memset(&portdef, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
- portdef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
- portdef.nVersion.nVersion = OMX_VERSION;
- portdef.nPortIndex = portIndex;
-
- // work out buffer requirements, check port is in the right state
- error = OMX_GetParameter(comp->comp, OMX_IndexParamPortDefinition, &portdef);
- if(error != OMX_ErrorNone || portdef.bEnabled != OMX_FALSE || portdef.nBufferCountActual == 0 || portdef.nBufferSize == 0)
- return -1;
-
- // check component is in the right state to accept buffers
- error = OMX_GetState(comp->comp, &state);
- if (error != OMX_ErrorNone || !(state == OMX_StateIdle || state == OMX_StateExecuting || state == OMX_StatePause))
- return -1;
-
- // send the command
- error = OMX_SendCommand(comp->comp, OMX_CommandPortEnable, portIndex, NULL);
- vc_assert(error == OMX_ErrorNone);
-
- for (i=0; i != portdef.nBufferCountActual; i++)
- {
- unsigned char *buf;
- if(ilclient_malloc)
- buf = ilclient_malloc(private, portdef.nBufferSize, portdef.nBufferAlignment, comp->bufname);
- else
- buf = vcos_malloc_aligned(portdef.nBufferSize, portdef.nBufferAlignment, comp->bufname);
-
- if(!buf)
- break;
-
- error = OMX_UseBuffer(comp->comp, end, portIndex, NULL, portdef.nBufferSize, buf);
- if(error != OMX_ErrorNone)
- {
- if(ilclient_free)
- ilclient_free(private, buf);
- else
- vcos_free(buf);
-
- break;
- }
- end = (OMX_BUFFERHEADERTYPE **) &((*end)->pAppPrivate);
- }
-
- // queue these buffers
- vcos_semaphore_wait(&comp->sema);
-
- if(portdef.eDir == OMX_DirInput)
- {
- *end = comp->in_list;
- comp->in_list = list;
- }
- else
- {
- *end = comp->out_list;
- comp->out_list = list;
- }
-
- vcos_semaphore_post(&comp->sema);
-
- if(i != portdef.nBufferCountActual ||
- ilclient_wait_for_command_complete(comp, OMX_CommandPortEnable, portIndex) < 0)
- {
- ilclient_disable_port_buffers(comp, portIndex, NULL, ilclient_free, private);
-
- // at this point the first command might have terminated with an error, which means that
- // the port is disabled before the disable_port_buffers function is called, so we're left
- // with the error bit set and an error event in the queue. Clear these now if they exist.
- ilclient_remove_event(comp, OMX_EventError, 0, 1, 1, 0);
-
- return -1;
- }
-
- // success
- return 0;
- }
-
-
- /***********************************************************
- * Name: ilclient_disable_port_buffers
- *
- * Description: disables a port on a given component which has
- * buffers supplied by the client.
- *
- * Returns: void
- ***********************************************************/
- void ilclient_disable_port_buffers(COMPONENT_T *comp, int portIndex,
- OMX_BUFFERHEADERTYPE *bufferList,
- ILCLIENT_FREE_T ilclient_free,
- void *private)
- {
- OMX_ERRORTYPE error;
- OMX_BUFFERHEADERTYPE *list = bufferList;
- OMX_BUFFERHEADERTYPE **head, *clist, *prev;
- OMX_PARAM_PORTDEFINITIONTYPE portdef;
- int num;
-
- // get the buffers off the relevant queue
- memset(&portdef, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
- portdef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
- portdef.nVersion.nVersion = OMX_VERSION;
- portdef.nPortIndex = portIndex;
-
- // work out buffer requirements, check port is in the right state
- error = OMX_GetParameter(comp->comp, OMX_IndexParamPortDefinition, &portdef);
- if(error != OMX_ErrorNone || portdef.bEnabled != OMX_TRUE || portdef.nBufferCountActual == 0 || portdef.nBufferSize == 0)
- return;
-
- num = portdef.nBufferCountActual;
-
- error = OMX_SendCommand(comp->comp, OMX_CommandPortDisable, portIndex, NULL);
- vc_assert(error == OMX_ErrorNone);
-
- while(num > 0)
- {
- VCOS_UNSIGNED set;
-
- if(list == NULL)
- {
- vcos_semaphore_wait(&comp->sema);
-
- // take buffers for this port off the relevant queue
- head = portdef.eDir == OMX_DirInput ? &comp->in_list : &comp->out_list;
- clist = *head;
- prev = NULL;
-
- while(clist)
- {
- if((portdef.eDir == OMX_DirInput ? clist->nInputPortIndex : clist->nOutputPortIndex) == portIndex)
- {
- OMX_BUFFERHEADERTYPE *pBuffer = clist;
-
- if(!prev)
- clist = *head = (OMX_BUFFERHEADERTYPE *) pBuffer->pAppPrivate;
- else
- clist = prev->pAppPrivate = (OMX_BUFFERHEADERTYPE *) pBuffer->pAppPrivate;
-
- pBuffer->pAppPrivate = list;
- list = pBuffer;
- }
- else
- {
- prev = clist;
- clist = (OMX_BUFFERHEADERTYPE *) &(clist->pAppPrivate);
- }
- }
-
- vcos_semaphore_post(&comp->sema);
- }
-
- while(list)
- {
- void *buf = list->pBuffer;
- OMX_BUFFERHEADERTYPE *next = list->pAppPrivate;
-
- error = OMX_FreeBuffer(comp->comp, portIndex, list);
- vc_assert(error == OMX_ErrorNone);
-
- if(ilclient_free)
- ilclient_free(private, buf);
- else
- vcos_free(buf);
-
- num--;
- list = next;
- }
-
- if(num)
- {
- OMX_U32 mask = ILCLIENT_PORT_DISABLED | ILCLIENT_EVENT_ERROR;
- mask |= (portdef.eDir == OMX_DirInput ? ILCLIENT_EMPTY_BUFFER_DONE : ILCLIENT_FILL_BUFFER_DONE);
-
- // also wait for command complete/error in case we didn't have all the buffers allocated
- vcos_event_flags_get(&comp->event, mask, VCOS_OR_CONSUME, -1, &set);
-
- if((set & ILCLIENT_EVENT_ERROR) && ilclient_remove_event(comp, OMX_EventError, 0, 1, 1, 0) >= 0)
- return;
-
- if((set & ILCLIENT_PORT_DISABLED) && ilclient_remove_event(comp, OMX_EventCmdComplete, OMX_CommandPortDisable, 0, portIndex, 0) >= 0)
- return;
- }
- }
-
- if(ilclient_wait_for_command_complete(comp, OMX_CommandPortDisable, portIndex) < 0)
- vc_assert(0);
- }
-
-
- /***********************************************************
- * Name: ilclient_setup_tunnel
- *
- * Description: creates a tunnel between components that require that
- * ports be inititially disabled, then enabled after tunnel setup. If
- * timeout is non-zero, it will initially wait until a port settings
- * changes message has been received by the output port. If port
- * streams are supported by the output port, the requested port stream
- * will be selected.
- *
- * Returns: 0 indicates success, negative indicates failure.
- * -1: a timeout waiting for the parameter changed
- * -2: an error was returned instead of parameter changed
- * -3: no streams are available from this port
- * -4: requested stream is not available from this port
- * -5: the data format was not acceptable to the sink
- ***********************************************************/
- int ilclient_setup_tunnel(TUNNEL_T *tunnel, unsigned int portStream, int timeout)
- {
- OMX_ERRORTYPE error;
- OMX_PARAM_U32TYPE param;
- OMX_STATETYPE state;
- int32_t status;
- int enable_error;
-
- // source component must at least be idle, not loaded
- error = OMX_GetState(tunnel->source->comp, &state);
- vc_assert(error == OMX_ErrorNone);
- if (state == OMX_StateLoaded && ilclient_change_component_state(tunnel->source, OMX_StateIdle) < 0)
- return -2;
-
- // wait for the port parameter changed from the source port
- if(timeout)
- {
- status = ilclient_wait_for_event(tunnel->source, OMX_EventPortSettingsChanged,
- tunnel->source_port, 0, -1, 1,
- ILCLIENT_PARAMETER_CHANGED | ILCLIENT_EVENT_ERROR, timeout);
-
- if (status < 0)
- {
- ilclient_debug_output(
- "ilclient: timed out waiting for port settings changed on port %d", tunnel->source_port);
- return status;
- }
- }
-
- // disable ports
- ilclient_disable_tunnel(tunnel);
-
- // if this source port uses port streams, we need to select one of them before proceeding
- // if getparameter causes an error that's fine, nothing needs selecting
- param.nSize = sizeof(OMX_PARAM_U32TYPE);
- param.nVersion.nVersion = OMX_VERSION;
- param.nPortIndex = tunnel->source_port;
- if (OMX_GetParameter(tunnel->source->comp, OMX_IndexParamNumAvailableStreams, ¶m) == OMX_ErrorNone)
- {
- if (param.nU32 == 0)
- {
- // no streams available
- // leave the source port disabled, and return a failure
- return -3;
- }
- if (param.nU32 <= portStream)
- {
- // requested stream not available
- // no streams available
- // leave the source port disabled, and return a failure
- return -4;
- }
-
- param.nU32 = portStream;
- error = OMX_SetParameter(tunnel->source->comp, OMX_IndexParamActiveStream, ¶m);
- vc_assert(error == OMX_ErrorNone);
- }
-
- // now create the tunnel
- error = OMX_SetupTunnel(tunnel->source->comp, tunnel->source_port, tunnel->sink->comp, tunnel->sink_port);
-
- enable_error = 0;
-
- if (error != OMX_ErrorNone || (enable_error=ilclient_enable_tunnel(tunnel)) < 0)
- {
- // probably format not compatible
- error = OMX_SetupTunnel(tunnel->source->comp, tunnel->source_port, NULL, 0);
- vc_assert(error == OMX_ErrorNone);
- error = OMX_SetupTunnel(tunnel->sink->comp, tunnel->sink_port, NULL, 0);
- vc_assert(error == OMX_ErrorNone);
-
- if(enable_error)
- {
- //Clean up the errors. This does risk removing an error that was nothing to do with this tunnel :-/
- ilclient_remove_event(tunnel->sink, OMX_EventError, 0, 1, 0, 1);
- ilclient_remove_event(tunnel->source, OMX_EventError, 0, 1, 0, 1);
- }
-
- ilclient_debug_output("ilclient: could not setup/enable tunnel (setup=0x%x,enable=%d)",
- error, enable_error);
- return -5;
- }
-
- return 0;
- }
-
- /***********************************************************
- * Name: ilclient_wait_for_event
- *
- * Description: waits for a given event to appear on a component event
- * list. If not immediately present, will wait on that components
- * event group for the given event flag.
- *
- * Returns: 0 indicates success, negative indicates failure.
- * -1: a timeout was received.
- * -2: an error event was received.
- * -3: a config change event was received.
- ***********************************************************/
- int 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)
- {
- int32_t status;
- uint32_t set;
-
- while (ilclient_remove_event(comp, event, nData1, ignore1, nData2, ignore2) < 0)
- {
- // if we want to be notified of errors, check the list for an error now
- // before blocking, the event flag may have been cleared already.
- if(event_flag & ILCLIENT_EVENT_ERROR)
- {
- ILEVENT_T *cur;
- ilclient_lock_events(comp->client);
- cur = comp->list;
- while(cur && cur->eEvent != OMX_EventError)
- cur = cur->next;
-
- if(cur)
- {
- // clear error flag
- vcos_event_flags_get(&comp->event, ILCLIENT_EVENT_ERROR, VCOS_OR_CONSUME, 0, &set);
- ilclient_unlock_events(comp->client);
- return -2;
- }
-
- ilclient_unlock_events(comp->client);
- }
- // check for config change event if we are asked to be notified of that
- if(event_flag & ILCLIENT_CONFIG_CHANGED)
- {
- ILEVENT_T *cur;
- ilclient_lock_events(comp->client);
- cur = comp->list;
- while(cur && cur->eEvent != OMX_EventParamOrConfigChanged)
- cur = cur->next;
-
- ilclient_unlock_events(comp->client);
-
- if(cur)
- return ilclient_remove_event(comp, event, nData1, ignore1, nData2, ignore2) == 0 ? 0 : -3;
- }
-
- status = vcos_event_flags_get(&comp->event, event_flag, VCOS_OR_CONSUME,
- suspend, &set);
- if (status != 0)
- return -1;
- if (set & ILCLIENT_EVENT_ERROR)
- return -2;
- if (set & ILCLIENT_CONFIG_CHANGED)
- return ilclient_remove_event(comp, event, nData1, ignore1, nData2, ignore2) == 0 ? 0 : -3;
- }
-
- return 0;
- }
-
-
-
- /***********************************************************
- * Name: ilclient_wait_for_command_complete_dual
- *
- * Description: Waits for an event signalling command completion. In
- * this version we may also return failure if there is an error event
- * that has terminated a command on a second component.
- *
- * Returns: 0 on success, -1 on failure of comp, -2 on failure of other
- ***********************************************************/
- int ilclient_wait_for_command_complete_dual(COMPONENT_T *comp, OMX_COMMANDTYPE command, OMX_U32 nData2, COMPONENT_T *other)
- {
- OMX_U32 mask = ILCLIENT_EVENT_ERROR;
- int ret = 0;
-
- switch(command) {
- case OMX_CommandStateSet: mask |= ILCLIENT_STATE_CHANGED; break;
- case OMX_CommandPortDisable: mask |= ILCLIENT_PORT_DISABLED; break;
- case OMX_CommandPortEnable: mask |= ILCLIENT_PORT_ENABLED; break;
- default: return -1;
- }
-
- if(other)
- other->related = comp;
-
- while(1)
- {
- ILEVENT_T *cur, *prev = NULL;
- VCOS_UNSIGNED set;
-
- ilclient_lock_events(comp->client);
-
- cur = comp->list;
- while(cur &&
- !(cur->eEvent == OMX_EventCmdComplete && cur->nData1 == command && cur->nData2 == nData2) &&
- !(cur->eEvent == OMX_EventError && cur->nData2 == 1))
- {
- prev = cur;
- cur = cur->next;
- }
-
- if(cur)
- {
- if(prev == NULL)
- comp->list = cur->next;
- else
- prev->next = cur->next;
-
- // work out whether this was a success or a fail event
- ret = cur->eEvent == OMX_EventCmdComplete || cur->nData1 == OMX_ErrorSameState ? 0 : -1;
-
- if(cur->eEvent == OMX_EventError)
- vcos_event_flags_get(&comp->event, ILCLIENT_EVENT_ERROR, VCOS_OR_CONSUME, 0, &set);
-
- // add back into spare list
- cur->next = comp->client->event_list;
- comp->client->event_list = cur;
- cur->eEvent = -1; // mark as unused
-
- ilclient_unlock_events(comp->client);
- break;
- }
- else if(other != NULL)
- {
- // check the other component for an error event that terminates a command
- cur = other->list;
- while(cur && !(cur->eEvent == OMX_EventError && cur->nData2 == 1))
- cur = cur->next;
-
- if(cur)
- {
- // we don't remove the event in this case, since the user
- // can confirm that this event errored by calling wait_for_command on the
- // other component
-
- ret = -2;
- ilclient_unlock_events(comp->client);
- break;
- }
- }
-
- ilclient_unlock_events(comp->client);
-
- vcos_event_flags_get(&comp->event, mask, VCOS_OR_CONSUME, VCOS_SUSPEND, &set);
- }
-
- if(other)
- other->related = NULL;
-
- return ret;
- }
-
-
- /***********************************************************
- * Name: ilclient_wait_for_command_complete
- *
- * Description: Waits for an event signalling command completion.
- *
- * Returns: 0 on success, -1 on failure.
- ***********************************************************/
- int ilclient_wait_for_command_complete(COMPONENT_T *comp, OMX_COMMANDTYPE command, OMX_U32 nData2)
- {
- return ilclient_wait_for_command_complete_dual(comp, command, nData2, NULL);
- }
-
- /***********************************************************
- * Name: ilclient_get_output_buffer
- *
- * Description: Returns an output buffer returned from a component
- * using the OMX_FillBufferDone callback from the output list for the
- * given component and port index.
- *
- * Returns: pointer to buffer if available, otherwise NULL
- ***********************************************************/
- OMX_BUFFERHEADERTYPE *ilclient_get_output_buffer(COMPONENT_T *comp, int portIndex, int block)
- {
- OMX_BUFFERHEADERTYPE *ret = NULL, *prev = NULL;
- VCOS_UNSIGNED set;
-
- do {
- vcos_semaphore_wait(&comp->sema);
- ret = comp->out_list;
- while(ret != NULL && ret->nOutputPortIndex != portIndex)
- {
- prev = ret;
- ret = ret->pAppPrivate;
- }
-
- if(ret)
- {
- if(prev == NULL)
- comp->out_list = ret->pAppPrivate;
- else
- prev->pAppPrivate = ret->pAppPrivate;
-
- ret->pAppPrivate = NULL;
- }
- vcos_semaphore_post(&comp->sema);
-
- if(block && !ret)
- vcos_event_flags_get(&comp->event, ILCLIENT_FILL_BUFFER_DONE, VCOS_OR_CONSUME, -1, &set);
-
- } while(block && !ret);
-
- return ret;
- }
-
- /***********************************************************
- * Name: ilclient_get_input_buffer
- *
- * Description: Returns an input buffer return from a component using
- * the OMX_EmptyBufferDone callback from the output list for the given
- * component and port index.
- *
- * Returns: pointer to buffer if available, otherwise NULL
- ***********************************************************/
- OMX_BUFFERHEADERTYPE *ilclient_get_input_buffer(COMPONENT_T *comp, int portIndex, int block)
- {
- OMX_BUFFERHEADERTYPE *ret = NULL, *prev = NULL;
-
- do {
- VCOS_UNSIGNED set;
-
- vcos_semaphore_wait(&comp->sema);
- ret = comp->in_list;
- while(ret != NULL && ret->nInputPortIndex != portIndex)
- {
- prev = ret;
- ret = ret->pAppPrivate;
- }
-
- if(ret)
- {
- if(prev == NULL)
- comp->in_list = ret->pAppPrivate;
- else
- prev->pAppPrivate = ret->pAppPrivate;
-
- ret->pAppPrivate = NULL;
- }
- vcos_semaphore_post(&comp->sema);
-
- if(block && !ret)
- vcos_event_flags_get(&comp->event, ILCLIENT_EMPTY_BUFFER_DONE, VCOS_OR_CONSUME, -1, &set);
-
- } while(block && !ret);
-
- return ret;
- }
-
- /***********************************************************
- * Name: ilclient_debug_output
- *
- * Description: prints a varg message to the log or the debug screen
- * under win32
- *
- * Returns: void
- ***********************************************************/
- void ilclient_debug_output(char *format, ...)
- {
- va_list args;
-
- va_start(args, format);
- vcos_vlog_info(format, args);
- va_end(args);
- }
-
- /******************************************************************************
- Static functions
- ******************************************************************************/
-
- /***********************************************************
- * Name: ilclient_lock_events
- *
- * Description: locks the client event structure
- *
- * Returns: void
- ***********************************************************/
- static void ilclient_lock_events(ILCLIENT_T *st)
- {
- vcos_semaphore_wait(&st->event_sema);
- }
-
- /***********************************************************
- * Name: ilclient_unlock_events
- *
- * Description: unlocks the client event structure
- *
- * Returns: void
- ***********************************************************/
- static void ilclient_unlock_events(ILCLIENT_T *st)
- {
- vcos_semaphore_post(&st->event_sema);
- }
-
- /***********************************************************
- * Name: ilclient_event_handler
- *
- * Description: event handler passed to core to use as component
- * callback
- *
- * Returns: success
- ***********************************************************/
- static OMX_ERRORTYPE 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)
- {
- COMPONENT_T *st = (COMPONENT_T *) pAppData;
- ILEVENT_T *event;
- OMX_ERRORTYPE error = OMX_ErrorNone;
-
- ilclient_lock_events(st->client);
-
- // go through the events on this component and remove any duplicates in the
- // existing list, since the client probably doesn't need them. it's better
- // than asserting when we run out.
- event = st->list;
- while(event != NULL)
- {
- ILEVENT_T **list = &(event->next);
- while(*list != NULL)
- {
- if((*list)->eEvent == event->eEvent &&
- (*list)->nData1 == event->nData1 &&
- (*list)->nData2 == event->nData2)
- {
- // remove this duplicate
- ILEVENT_T *rem = *list;
- ilclient_debug_output("%s: removing %d/%d/%d", st->name, event->eEvent, event->nData1, event->nData2);
- *list = rem->next;
- rem->eEvent = -1;
- rem->next = st->client->event_list;
- st->client->event_list = rem;
- }
- else
- list = &((*list)->next);
- }
-
- event = event->next;
- }
-
- vc_assert(st->client->event_list);
- event = st->client->event_list;
-
- switch (eEvent) {
- case OMX_EventCmdComplete:
- switch (nData1) {
- case OMX_CommandStateSet:
- ilclient_debug_output("%s: callback state changed (%s)", st->name, states[nData2]);
- vcos_event_flags_set(&st->event, ILCLIENT_STATE_CHANGED, VCOS_OR);
- break;
- case OMX_CommandPortDisable:
- ilclient_debug_output("%s: callback port disable %d", st->name, nData2);
- vcos_event_flags_set(&st->event, ILCLIENT_PORT_DISABLED, VCOS_OR);
- break;
- case OMX_CommandPortEnable:
- ilclient_debug_output("%s: callback port enable %d", st->name, nData2);
- vcos_event_flags_set(&st->event, ILCLIENT_PORT_ENABLED, VCOS_OR);
- break;
- case OMX_CommandFlush:
- ilclient_debug_output("%s: callback port flush %d", st->name, nData2);
- vcos_event_flags_set(&st->event, ILCLIENT_PORT_FLUSH, VCOS_OR);
- break;
- case OMX_CommandMarkBuffer:
- ilclient_debug_output("%s: callback mark buffer %d", st->name, nData2);
- vcos_event_flags_set(&st->event, ILCLIENT_MARKED_BUFFER, VCOS_OR);
- break;
- default:
- vc_assert(0);
- }
- break;
- case OMX_EventError:
- {
- // check if this component failed a command, and we have to notify another command
- // of this failure
- if(nData2 == 1 && st->related != NULL)
- vcos_event_flags_set(&st->related->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
-
- error = nData1;
- switch (error) {
- case OMX_ErrorPortUnpopulated:
- if (st->error_mask & ILCLIENT_ERROR_UNPOPULATED)
- {
- ilclient_debug_output("%s: ignore error: port unpopulated (%d)", st->name, nData2);
- event = NULL;
- break;
- }
- ilclient_debug_output("%s: port unpopulated %x (%d)", st->name, error, nData2);
- vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
- break;
- case OMX_ErrorSameState:
- if (st->error_mask & ILCLIENT_ERROR_SAMESTATE)
- {
- ilclient_debug_output("%s: ignore error: same state (%d)", st->name, nData2);
- event = NULL;
- break;
- }
- ilclient_debug_output("%s: same state %x (%d)", st->name, error, nData2);
- vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
- break;
- case OMX_ErrorBadParameter:
- if (st->error_mask & ILCLIENT_ERROR_BADPARAMETER)
- {
- ilclient_debug_output("%s: ignore error: bad parameter (%d)", st->name, nData2);
- event = NULL;
- break;
- }
- ilclient_debug_output("%s: bad parameter %x (%d)", st->name, error, nData2);
- vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
- break;
- case OMX_ErrorIncorrectStateTransition:
- ilclient_debug_output("%s: incorrect state transition %x (%d)", st->name, error, nData2);
- vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
- break;
- case OMX_ErrorBadPortIndex:
- ilclient_debug_output("%s: bad port index %x (%d)", st->name, error, nData2);
- vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
- break;
- case OMX_ErrorStreamCorrupt:
- ilclient_debug_output("%s: stream corrupt %x (%d)", st->name, error, nData2);
- vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
- break;
- case OMX_ErrorInsufficientResources:
- ilclient_debug_output("%s: insufficient resources %x (%d)", st->name, error, nData2);
- vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
- break;
- case OMX_ErrorUnsupportedSetting:
- ilclient_debug_output("%s: unsupported setting %x (%d)", st->name, error, nData2);
- vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
- break;
- case OMX_ErrorOverflow:
- ilclient_debug_output("%s: overflow %x (%d)", st->name, error, nData2);
- vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
- break;
- case OMX_ErrorDiskFull:
- ilclient_debug_output("%s: disk full %x (%d)", st->name, error, nData2);
- //we do not set the error
- break;
- case OMX_ErrorMaxFileSize:
- ilclient_debug_output("%s: max file size %x (%d)", st->name, error, nData2);
- //we do not set the error
- break;
- case OMX_ErrorDrmUnauthorised:
- ilclient_debug_output("%s: drm file is unauthorised %x (%d)", st->name, error, nData2);
- vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
- break;
- case OMX_ErrorDrmExpired:
- ilclient_debug_output("%s: drm file has expired %x (%d)", st->name, error, nData2);
- vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
- break;
- case OMX_ErrorDrmGeneral:
- ilclient_debug_output("%s: drm library error %x (%d)", st->name, error, nData2);
- vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
- break;
- default:
- vc_assert(0);
- ilclient_debug_output("%s: unexpected error %x (%d)", st->name, error, nData2);
- vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
- break;
- }
- }
- break;
- case OMX_EventBufferFlag:
- ilclient_debug_output("%s: buffer flag %d/%x", st->name, nData1, nData2);
- if (nData2 & OMX_BUFFERFLAG_EOS)
- {
- vcos_event_flags_set(&st->event, ILCLIENT_BUFFER_FLAG_EOS, VCOS_OR);
- nData2 = OMX_BUFFERFLAG_EOS;
- }
- else
- vc_assert(0);
- break;
- case OMX_EventPortSettingsChanged:
- ilclient_debug_output("%s: port settings changed %d", st->name, nData1);
- vcos_event_flags_set(&st->event, ILCLIENT_PARAMETER_CHANGED, VCOS_OR);
- break;
- case OMX_EventMark:
- ilclient_debug_output("%s: buffer mark %p", st->name, pEventData);
- vcos_event_flags_set(&st->event, ILCLIENT_BUFFER_MARK, VCOS_OR);
- break;
- case OMX_EventParamOrConfigChanged:
- ilclient_debug_output("%s: param/config 0x%X on port %d changed", st->name, nData2, nData1);
- vcos_event_flags_set(&st->event, ILCLIENT_CONFIG_CHANGED, VCOS_OR);
- break;
- default:
- vc_assert(0);
- break;
- }
-
- if (event)
- {
- // fill in details
- event->eEvent = eEvent;
- event->nData1 = nData1;
- event->nData2 = nData2;
- event->pEventData = pEventData;
-
- // remove from top of spare list
- st->client->event_list = st->client->event_list->next;
-
- // put at head of component event queue
- event->next = st->list;
- st->list = event;
- }
- ilclient_unlock_events(st->client);
-
- // now call any callbacks without the event lock so the client can
- // remove the event in context
- switch(eEvent) {
- case OMX_EventError:
- if(event && st->client->error_callback)
- st->client->error_callback(st->client->error_callback_data, st, error);
- break;
- case OMX_EventBufferFlag:
- if ((nData2 & OMX_BUFFERFLAG_EOS) && st->client->eos_callback)
- st->client->eos_callback(st->client->eos_callback_data, st, nData1);
- break;
- case OMX_EventPortSettingsChanged:
- if (st->client->port_settings_callback)
- st->client->port_settings_callback(st->client->port_settings_callback_data, st, nData1);
- break;
- case OMX_EventParamOrConfigChanged:
- if (st->client->configchanged_callback)
- st->client->configchanged_callback(st->client->configchanged_callback_data, st, nData2);
- break;
- default:
- // ignore
- break;
- }
-
- return OMX_ErrorNone;
- }
-
- /***********************************************************
- * Name: ilclient_empty_buffer_done
- *
- * Description: passed to core to use as component callback, puts
- * buffer on list
- *
- * Returns:
- ***********************************************************/
- static OMX_ERRORTYPE ilclient_empty_buffer_done(OMX_IN OMX_HANDLETYPE hComponent,
- OMX_IN OMX_PTR pAppData,
- OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
- {
- COMPONENT_T *st = (COMPONENT_T *) pAppData;
- OMX_BUFFERHEADERTYPE *list;
-
- ilclient_debug_output("%s: empty buffer done %p", st->name, pBuffer);
-
- vcos_semaphore_wait(&st->sema);
- // insert at end of the list, so we process buffers in
- // the same order
- list = st->in_list;
- while(list && list->pAppPrivate)
- list = list->pAppPrivate;
-
- if(!list)
- st->in_list = pBuffer;
- else
- list->pAppPrivate = pBuffer;
-
- pBuffer->pAppPrivate = NULL;
- vcos_semaphore_post(&st->sema);
-
- vcos_event_flags_set(&st->event, ILCLIENT_EMPTY_BUFFER_DONE, VCOS_OR);
-
- if (st->client->empty_buffer_done_callback)
- st->client->empty_buffer_done_callback(st->client->empty_buffer_done_callback_data, st);
-
- return OMX_ErrorNone;
- }
-
- /***********************************************************
- * Name: ilclient_empty_buffer_done_error
- *
- * Description: passed to core to use as component callback, asserts
- * on use as client not expecting component to use this callback.
- *
- * Returns:
- ***********************************************************/
- static OMX_ERRORTYPE ilclient_empty_buffer_done_error(OMX_IN OMX_HANDLETYPE hComponent,
- OMX_IN OMX_PTR pAppData,
- OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
- {
- vc_assert(0);
- return OMX_ErrorNone;
- }
-
- /***********************************************************
- * Name: ilclient_fill_buffer_done
- *
- * Description: passed to core to use as component callback, puts
- * buffer on list
- *
- * Returns:
- ***********************************************************/
- static OMX_ERRORTYPE ilclient_fill_buffer_done(OMX_OUT OMX_HANDLETYPE hComponent,
- OMX_OUT OMX_PTR pAppData,
- OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer)
- {
- COMPONENT_T *st = (COMPONENT_T *) pAppData;
- OMX_BUFFERHEADERTYPE *list;
-
- ilclient_debug_output("%s: fill buffer done %p", st->name, pBuffer);
-
- vcos_semaphore_wait(&st->sema);
- // insert at end of the list, so we process buffers in
- // the correct order
- list = st->out_list;
- while(list && list->pAppPrivate)
- list = list->pAppPrivate;
-
- if(!list)
- st->out_list = pBuffer;
- else
- list->pAppPrivate = pBuffer;
-
- pBuffer->pAppPrivate = NULL;
- vcos_semaphore_post(&st->sema);
-
- vcos_event_flags_set(&st->event, ILCLIENT_FILL_BUFFER_DONE, VCOS_OR);
-
- if (st->client->fill_buffer_done_callback)
- st->client->fill_buffer_done_callback(st->client->fill_buffer_done_callback_data, st);
-
- return OMX_ErrorNone;
- }
-
- /***********************************************************
- * Name: ilclient_fill_buffer_done_error
- *
- * Description: passed to core to use as component callback, asserts
- * on use as client not expecting component to use this callback.
- *
- * Returns:
- ***********************************************************/
- static OMX_ERRORTYPE ilclient_fill_buffer_done_error(OMX_OUT OMX_HANDLETYPE hComponent,
- OMX_OUT OMX_PTR pAppData,
- OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer)
- {
- vc_assert(0);
- return OMX_ErrorNone;
- }
-
-
-
- OMX_HANDLETYPE ilclient_get_handle(COMPONENT_T *comp)
- {
- vcos_assert(comp);
- return comp->comp;
- }
-
-
- static struct {
- OMX_PORTDOMAINTYPE dom;
- int param;
- } port_types[] = {
- { OMX_PortDomainVideo, OMX_IndexParamVideoInit },
- { OMX_PortDomainAudio, OMX_IndexParamAudioInit },
- { OMX_PortDomainImage, OMX_IndexParamImageInit },
- { OMX_PortDomainOther, OMX_IndexParamOtherInit },
- };
-
- int ilclient_get_port_index(COMPONENT_T *comp, OMX_DIRTYPE dir, OMX_PORTDOMAINTYPE type, int index)
- {
- uint32_t i;
- // for each possible port type...
- for (i=0; i<sizeof(port_types)/sizeof(port_types[0]); i++)
- {
- if ((port_types[i].dom == type) || (type == (OMX_PORTDOMAINTYPE) -1))
- {
- OMX_PORT_PARAM_TYPE param;
- OMX_ERRORTYPE error;
- uint32_t j;
-
- param.nSize = sizeof(param);
- param.nVersion.nVersion = OMX_VERSION;
- error = OMX_GetParameter(ILC_GET_HANDLE(comp), port_types[i].param, ¶m);
- assert(error == OMX_ErrorNone);
-
- // for each port of this type...
- for (j=0; j<param.nPorts; j++)
- {
- int port = param.nStartPortNumber+j;
-
- OMX_PARAM_PORTDEFINITIONTYPE portdef;
- portdef.nSize = sizeof(portdef);
- portdef.nVersion.nVersion = OMX_VERSION;
- portdef.nPortIndex = port;
-
- error = OMX_GetParameter(ILC_GET_HANDLE(comp), OMX_IndexParamPortDefinition, &portdef);
- assert(error == OMX_ErrorNone);
-
- if (portdef.eDir == dir)
- {
- if (index-- == 0)
- return port;
- }
- }
- }
- }
- return -1;
- }
-
- int ilclient_suggest_bufsize(COMPONENT_T *comp, OMX_U32 nBufSizeHint)
- {
- OMX_PARAM_BRCMOUTPUTBUFFERSIZETYPE param;
- OMX_ERRORTYPE error;
-
- param.nSize = sizeof(param);
- param.nVersion.nVersion = OMX_VERSION;
- param.nBufferSize = nBufSizeHint;
- error = OMX_SetParameter(ILC_GET_HANDLE(comp), OMX_IndexParamBrcmOutputBufferSize,
- ¶m);
- assert(error == OMX_ErrorNone);
-
- return (error == OMX_ErrorNone) ? 0 : -1;
- }
-
- unsigned int ilclient_stack_size(void)
- {
- return ILCLIENT_THREAD_DEFAULT_STACK_SIZE;
- }
-
|