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