1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, 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
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON 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
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28#include "mmal.h"
29#include "util/mmal_util.h"
30#include "util/mmal_graph.h"
31#include "core/mmal_component_private.h"
32#include "core/mmal_port_private.h"
33#include "mmal_logging.h"
34
35#define GRAPH_CONNECTIONS_MAX 16
36#define PROCESSING_TIME_MAX 20000
37
38/*****************************************************************************/
39
40/** Private context for our graph.
41 * This also acts as a MMAL_COMPONENT_MODULE_T for when components are instantiated from graphs */
42typedef struct MMAL_COMPONENT_MODULE_T
43{
44 MMAL_GRAPH_T graph; /**< Must be the first member! */
45
46 MMAL_COMPONENT_T *component[GRAPH_CONNECTIONS_MAX];
47 MMAL_GRAPH_TOPOLOGY_T topology[GRAPH_CONNECTIONS_MAX];
48 unsigned int component_num;
49
50 MMAL_CONNECTION_T *connection[GRAPH_CONNECTIONS_MAX];
51 unsigned int connection_num;
52 unsigned int connection_current;
53
54 MMAL_PORT_T *input[GRAPH_CONNECTIONS_MAX];
55 unsigned int input_num;
56 MMAL_PORT_T *output[GRAPH_CONNECTIONS_MAX];
57 unsigned int output_num;
58 MMAL_PORT_T *clock[GRAPH_CONNECTIONS_MAX];
59 unsigned int clock_num;
60
61 MMAL_COMPONENT_T *graph_component;
62
63 MMAL_BOOL_T stop_thread; /**< informs the worker thread to exit */
64 VCOS_THREAD_T thread; /**< worker thread which processes all internal connections */
65 VCOS_SEMAPHORE_T sema; /**< informs the worker thread that buffers are available */
66
67 MMAL_GRAPH_EVENT_CB event_cb; /**< callback for sending control port events to the client */
68 void *event_cb_data; /**< callback data supplied by the client */
69
70} MMAL_GRAPH_PRIVATE_T;
71
72typedef MMAL_GRAPH_PRIVATE_T MMAL_COMPONENT_MODULE_T;
73
74/*****************************************************************************/
75static MMAL_STATUS_T mmal_component_create_from_graph(const char *name, MMAL_COMPONENT_T *component);
76static MMAL_BOOL_T graph_do_processing(MMAL_GRAPH_PRIVATE_T *graph);
77static void graph_process_buffer(MMAL_GRAPH_PRIVATE_T *graph_private,
78 MMAL_CONNECTION_T *connection, MMAL_BUFFER_HEADER_T *buffer);
79
80/*****************************************************************************/
81static void graph_control_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
82{
83 MMAL_GRAPH_PRIVATE_T *graph = (MMAL_GRAPH_PRIVATE_T *)port->userdata;
84
85 LOG_TRACE("port: %s(%p), buffer: %p, event: %4.4s", port->name, port,
86 buffer, (char *)&buffer->cmd);
87
88 if (graph->event_cb)
89 {
90 graph->event_cb((MMAL_GRAPH_T *)graph, port, buffer, graph->event_cb_data);
91 }
92 else
93 {
94 LOG_ERROR("event lost on port %i,%i (event callback not defined)",
95 (int)port->type, (int)port->index);
96 mmal_buffer_header_release(buffer);
97 }
98}
99
100/*****************************************************************************/
101static void graph_connection_cb(MMAL_CONNECTION_T *connection)
102{
103 MMAL_GRAPH_PRIVATE_T *graph = (MMAL_GRAPH_PRIVATE_T *)connection->user_data;
104 MMAL_BUFFER_HEADER_T *buffer;
105
106 if (connection->flags == MMAL_CONNECTION_FLAG_DIRECT &&
107 (buffer = mmal_queue_get(connection->queue)) != NULL)
108 {
109 graph_process_buffer(graph, connection, buffer);
110 return;
111 }
112
113 vcos_semaphore_post(&graph->sema);
114}
115
116/*****************************************************************************/
117static void* graph_worker_thread(void* ctx)
118{
119 MMAL_GRAPH_PRIVATE_T *graph = (MMAL_GRAPH_PRIVATE_T *)ctx;
120
121 while (1)
122 {
123 vcos_semaphore_wait(&graph->sema);
124 if (graph->stop_thread)
125 break;
126 while(graph_do_processing(graph));
127 }
128
129 LOG_TRACE("worker thread exit %p", graph);
130
131 return 0;
132}
133
134/*****************************************************************************/
135static void graph_stop_worker_thread(MMAL_GRAPH_PRIVATE_T *graph)
136{
137 graph->stop_thread = MMAL_TRUE;
138 vcos_semaphore_post(&graph->sema);
139 vcos_thread_join(&graph->thread, NULL);
140}
141
142/*****************************************************************************/
143MMAL_STATUS_T mmal_graph_create(MMAL_GRAPH_T **graph, unsigned int userdata_size)
144{
145 MMAL_GRAPH_PRIVATE_T *private;
146
147 LOG_TRACE("graph %p, userdata_size %u", graph, userdata_size);
148
149 /* Sanity checking */
150 if (!graph)
151 return MMAL_EINVAL;
152
153 private = vcos_calloc(1, sizeof(MMAL_GRAPH_PRIVATE_T) + userdata_size, "mmal connection graph");
154 if (!private)
155 return MMAL_ENOMEM;
156 *graph = &private->graph;
157 if (userdata_size)
158 (*graph)->userdata = (struct MMAL_GRAPH_USERDATA_T *)&private[1];
159
160 if (vcos_semaphore_create(&private->sema, "mmal graph sema", 0) != VCOS_SUCCESS)
161 {
162 LOG_ERROR("failed to create semaphore %p", graph);
163 vcos_free(private);
164 return MMAL_ENOSPC;
165 }
166
167 return MMAL_SUCCESS;
168}
169
170/*****************************************************************************/
171MMAL_STATUS_T mmal_graph_destroy(MMAL_GRAPH_T *graph)
172{
173 unsigned i;
174 MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
175
176 if (!graph)
177 return MMAL_EINVAL;
178
179 LOG_TRACE("%p", graph);
180
181 /* Notify client of destruction */
182 if (graph->pf_destroy)
183 graph->pf_destroy(graph);
184
185 for (i = 0; i < private->connection_num; i++)
186 mmal_connection_release(private->connection[i]);
187
188 for (i = 0; i < private->component_num; i++)
189 mmal_component_release(private->component[i]);
190
191 vcos_semaphore_delete(&private->sema);
192
193 vcos_free(graph);
194 return MMAL_SUCCESS;
195}
196
197/*****************************************************************************/
198MMAL_STATUS_T mmal_graph_add_component(MMAL_GRAPH_T *graph, MMAL_COMPONENT_T *component)
199{
200 MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
201
202 LOG_TRACE("graph: %p, component: %s(%p)", graph, component ? component->name: 0, component);
203
204 if (!component)
205 return MMAL_EINVAL;
206
207 if (private->component_num >= GRAPH_CONNECTIONS_MAX)
208 {
209 LOG_ERROR("no space for component %s", component->name);
210 return MMAL_ENOSPC;
211 }
212
213 mmal_component_acquire(component);
214 private->component[private->component_num++] = component;
215
216 return MMAL_SUCCESS;
217}
218
219/*****************************************************************************/
220MMAL_STATUS_T mmal_graph_component_topology(MMAL_GRAPH_T *graph, MMAL_COMPONENT_T *component,
221 MMAL_GRAPH_TOPOLOGY_T topology, int8_t *input, unsigned int input_num,
222 int8_t *output, unsigned int output_num)
223{
224 MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
225 MMAL_PARAM_UNUSED(input); MMAL_PARAM_UNUSED(input_num);
226 MMAL_PARAM_UNUSED(output); MMAL_PARAM_UNUSED(output_num);
227 unsigned int i;
228
229 LOG_TRACE("graph: %p, component: %s(%p)", graph, component ? component->name: 0, component);
230
231 if (!component)
232 return MMAL_EINVAL;
233
234 for (i = 0; i < private->component_num; i++)
235 if (component == private->component[i])
236 break;
237
238 if (i == private->component_num)
239 return MMAL_EINVAL; /* Component not found */
240
241 if (topology > MMAL_GRAPH_TOPOLOGY_STRAIGHT)
242 return MMAL_ENOSYS; /* Currently not supported */
243
244 private->topology[i] = topology;
245
246 return MMAL_SUCCESS;
247}
248
249/*****************************************************************************/
250MMAL_STATUS_T mmal_graph_add_connection(MMAL_GRAPH_T *graph, MMAL_CONNECTION_T *cx)
251{
252 MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
253
254 LOG_TRACE("graph: %p, connection: %s(%p)", graph, cx ? cx->name: 0, cx);
255
256 if (!cx)
257 return MMAL_EINVAL;
258
259 if (private->connection_num >= GRAPH_CONNECTIONS_MAX)
260 {
261 LOG_ERROR("no space for connection %s", cx->name);
262 return MMAL_ENOSPC;
263 }
264
265 mmal_connection_acquire(cx);
266 private->connection[private->connection_num++] = cx;
267 return MMAL_SUCCESS;
268}
269
270/*****************************************************************************/
271MMAL_STATUS_T mmal_graph_add_port(MMAL_GRAPH_T *graph, MMAL_PORT_T *port)
272{
273 MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
274 MMAL_PORT_T **list;
275 unsigned int *list_num;
276
277 LOG_TRACE("graph: %p, port: %s(%p)", graph, port ? port->name: 0, port);
278
279 if (!port)
280 return MMAL_EINVAL;
281
282 switch (port->type)
283 {
284 case MMAL_PORT_TYPE_INPUT:
285 list = private->input;
286 list_num = &private->input_num;
287 break;
288 case MMAL_PORT_TYPE_OUTPUT:
289 list = private->output;
290 list_num = &private->output_num;
291 break;
292 case MMAL_PORT_TYPE_CLOCK:
293 list = private->clock;
294 list_num = &private->clock_num;
295 break;
296 default:
297 return MMAL_EINVAL;
298 }
299
300 if (*list_num >= GRAPH_CONNECTIONS_MAX)
301 {
302 LOG_ERROR("no space for port %s", port->name);
303 return MMAL_ENOSPC;
304 }
305
306 list[(*list_num)++] = port;
307 return MMAL_SUCCESS;
308}
309
310/*****************************************************************************/
311MMAL_STATUS_T mmal_graph_new_component(MMAL_GRAPH_T *graph, const char *name,
312 MMAL_COMPONENT_T **component)
313{
314 MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
315 MMAL_COMPONENT_T *comp;
316 MMAL_STATUS_T status;
317
318 LOG_TRACE("graph: %p, name: %s, component: %p", graph, name, component);
319
320 if (private->component_num >= GRAPH_CONNECTIONS_MAX)
321 {
322 LOG_ERROR("no space for component %s", name);
323 return MMAL_ENOSPC;
324 }
325
326 status = mmal_component_create(name, &comp);
327 if (status != MMAL_SUCCESS)
328 {
329 LOG_ERROR("could not create component %s (%i)", name, status);
330 return status;
331 }
332
333 private->component[private->component_num++] = comp;
334 if (component)
335 {
336 mmal_component_acquire(comp);
337 *component = comp;
338 }
339
340 return MMAL_SUCCESS;
341}
342
343/*****************************************************************************/
344MMAL_STATUS_T mmal_graph_new_connection(MMAL_GRAPH_T *graph, MMAL_PORT_T *out, MMAL_PORT_T *in,
345 uint32_t flags, MMAL_CONNECTION_T **connection)
346{
347 MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
348 MMAL_CONNECTION_T *cx;
349 MMAL_STATUS_T status;
350
351 if (!out || !in)
352 return MMAL_EINVAL;
353 if (out->type == MMAL_PORT_TYPE_CLOCK && in->type != MMAL_PORT_TYPE_CLOCK)
354 return MMAL_EINVAL;
355 if (out->type != MMAL_PORT_TYPE_CLOCK &&
356 (out->type != MMAL_PORT_TYPE_OUTPUT || in->type != MMAL_PORT_TYPE_INPUT))
357 return MMAL_EINVAL;
358
359 LOG_TRACE("graph: %p, out: %s(%p), in: %s(%p), flags %x, connection: %p",
360 graph, out->name, out, in->name, in, (int)flags, connection);
361
362 if (private->connection_num >= GRAPH_CONNECTIONS_MAX)
363 {
364 LOG_ERROR("no space for connection %s/%s", out->name, in->name);
365 return MMAL_ENOSPC;
366 }
367
368 status = mmal_connection_create(&cx, out, in, flags);
369 if (status != MMAL_SUCCESS)
370 return status;
371
372 private->connection[private->connection_num++] = cx;
373 if (connection)
374 {
375 mmal_connection_acquire(cx);
376 *connection = cx;
377 }
378
379 return MMAL_SUCCESS;
380}
381
382/*****************************************************************************/
383MMAL_STATUS_T mmal_graph_enable(MMAL_GRAPH_T *graph, MMAL_GRAPH_EVENT_CB cb, void *cb_data)
384{
385 MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
386 MMAL_STATUS_T status = MMAL_SUCCESS;
387 unsigned int i;
388
389 LOG_TRACE("graph: %p", graph);
390
391 if (vcos_thread_create(&private->thread, "mmal graph thread", NULL,
392 graph_worker_thread, private) != VCOS_SUCCESS)
393 {
394 LOG_ERROR("failed to create worker thread %p", graph);
395 return MMAL_ENOSPC;
396 }
397
398 private->event_cb = cb;
399 private->event_cb_data = cb_data;
400
401 /* Enable all control ports */
402 for (i = 0; i < private->component_num; i++)
403 {
404 private->component[i]->control->userdata = (void *)private;
405 status = mmal_port_enable(private->component[i]->control, graph_control_cb);
406 if (status != MMAL_SUCCESS)
407 LOG_ERROR("could not enable port %s", private->component[i]->control->name);
408 }
409
410 /* Enable all our connections */
411 for (i = 0; i < private->connection_num; i++)
412 {
413 MMAL_CONNECTION_T *cx = private->connection[i];
414
415 cx->callback = graph_connection_cb;
416 cx->user_data = private;
417
418 status = mmal_connection_enable(cx);
419 if (status != MMAL_SUCCESS)
420 goto error;
421 }
422
423 /* Trigger the worker thread to populate the output ports with empty buffers */
424 vcos_semaphore_post(&private->sema);
425 return status;
426
427 error:
428 graph_stop_worker_thread(private);
429 return status;
430}
431
432/*****************************************************************************/
433MMAL_STATUS_T mmal_graph_disable(MMAL_GRAPH_T *graph)
434{
435 MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
436 MMAL_STATUS_T status = MMAL_SUCCESS;
437 unsigned int i;
438
439 LOG_TRACE("graph: %p", graph);
440
441 graph_stop_worker_thread(private);
442
443 /* Disable all our connections */
444 for (i = 0; i < private->connection_num; i++)
445 {
446 status = mmal_connection_disable(private->connection[i]);
447 if (status != MMAL_SUCCESS)
448 break;
449 }
450
451 return status;
452}
453
454/*****************************************************************************/
455MMAL_STATUS_T mmal_graph_build(MMAL_GRAPH_T *graph,
456 const char *name, MMAL_COMPONENT_T **component)
457{
458 LOG_TRACE("graph: %p, name: %s, component: %p", graph, name, component);
459 return mmal_component_create_with_constructor(name, mmal_component_create_from_graph,
460 (MMAL_GRAPH_PRIVATE_T *)graph, component);
461}
462
463/*****************************************************************************/
464MMAL_STATUS_T mmal_graph_component_constructor(const char *name,
465 MMAL_COMPONENT_T *component)
466{
467 LOG_TRACE("name: %s, component: %p", name, component);
468 return mmal_component_create_from_graph(name, component);
469}
470
471/*****************************************************************************/
472static void graph_component_control_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
473{
474 MMAL_COMPONENT_T *graph_component = (MMAL_COMPONENT_T *)port->userdata;
475 MMAL_GRAPH_PRIVATE_T *graph_private = graph_component->priv->module;
476 MMAL_STATUS_T status;
477
478 LOG_TRACE("%s(%p),%p,%4.4s", port->name, port, buffer, (char *)&buffer->cmd);
479
480 /* Call user defined function first */
481 if (graph_private->graph.pf_control_callback)
482 {
483 status = graph_private->graph.pf_control_callback(&graph_private->graph,
484 port, buffer);
485 if (status != MMAL_ENOSYS)
486 return;
487 }
488
489 /* Forward the event on the graph control port */
490 mmal_port_event_send(graph_component->control, buffer);
491}
492
493/*****************************************************************************/
494static void graph_component_connection_cb(MMAL_CONNECTION_T *connection)
495{
496 MMAL_COMPONENT_T *component = (MMAL_COMPONENT_T *)connection->user_data;
497 MMAL_BUFFER_HEADER_T *buffer;
498
499 if (connection->flags == MMAL_CONNECTION_FLAG_DIRECT &&
500 (buffer = mmal_queue_get(connection->queue)) != NULL)
501 {
502 graph_process_buffer((MMAL_GRAPH_PRIVATE_T *)component->priv->module,
503 connection, buffer);
504 return;
505 }
506
507 mmal_component_action_trigger(component);
508}
509
510/*****************************************************************************/
511static void graph_port_event_handler(MMAL_CONNECTION_T *connection,
512 MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
513{
514 MMAL_STATUS_T status;
515
516 LOG_TRACE("port: %s(%p), buffer: %p, event: %4.4s", port->name, port,
517 buffer, (char *)&buffer->cmd);
518
519 if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED && port->type == MMAL_PORT_TYPE_OUTPUT)
520 {
521 MMAL_EVENT_FORMAT_CHANGED_T *event = mmal_event_format_changed_get(buffer);
522 if (event)
523 {
524 LOG_DEBUG("----------Port format changed----------");
525 mmal_log_dump_port(port);
526 LOG_DEBUG("-----------------to---------------------");
527 mmal_log_dump_format(event->format);
528 LOG_DEBUG(" buffers num (opt %i, min %i), size (opt %i, min: %i)",
529 event->buffer_num_recommended, event->buffer_num_min,
530 event->buffer_size_recommended, event->buffer_size_min);
531 LOG_DEBUG("----------------------------------------");
532 }
533
534 status = mmal_connection_event_format_changed(connection, buffer);
535 }
536
537 else
538 status = MMAL_SUCCESS; /* FIXME: ignore any other event for now */
539
540 mmal_buffer_header_release(buffer);
541
542 if (status != MMAL_SUCCESS)
543 mmal_event_error_send(port->component, status);
544}
545
546/*****************************************************************************/
547static void graph_process_buffer(MMAL_GRAPH_PRIVATE_T *graph_private,
548 MMAL_CONNECTION_T *connection, MMAL_BUFFER_HEADER_T *buffer)
549{
550 MMAL_STATUS_T status;
551
552 /* Call user defined function first */
553 if (graph_private->graph.pf_connection_buffer)
554 {
555 status = graph_private->graph.pf_connection_buffer(&graph_private->graph, connection, buffer);
556 if (status != MMAL_ENOSYS)
557 return;
558 }
559
560 if (buffer->cmd)
561 {
562 graph_port_event_handler(connection, connection->out, buffer);
563 return;
564 }
565
566 status = mmal_port_send_buffer(connection->in, buffer);
567 if (status != MMAL_SUCCESS)
568 {
569 LOG_ERROR("%s(%p) could not send buffer to %s(%p) (%s)",
570 connection->out->name, connection->out,
571 connection->in->name, connection->in,
572 mmal_status_to_string(status));
573 mmal_buffer_header_release(buffer);
574 mmal_event_error_send(connection->out->component, status);
575 }
576}
577
578/*****************************************************************************/
579static MMAL_BOOL_T graph_do_processing(MMAL_GRAPH_PRIVATE_T *graph_private)
580{
581 MMAL_BUFFER_HEADER_T *buffer;
582 MMAL_BOOL_T run_again = 0;
583 MMAL_STATUS_T status;
584 unsigned int i, j;
585
586 /* Process all the empty buffers first */
587 for (i = 0, j = graph_private->connection_current;
588 i < graph_private->connection_num; i++, j++)
589 {
590 MMAL_CONNECTION_T *connection =
591 graph_private->connection[j%graph_private->connection_num];
592
593 if ((connection->flags & MMAL_CONNECTION_FLAG_TUNNELLING) ||
594 !connection->pool)
595 continue; /* Nothing else to do in tunnelling mode */
596
597 /* Send empty buffers to the output port of the connection */
598 while ((buffer = mmal_queue_get(connection->pool->queue)) != NULL)
599 {
600 run_again = 1;
601
602 status = mmal_port_send_buffer(connection->out, buffer);
603 if (status != MMAL_SUCCESS)
604 {
605 if (connection->out->is_enabled)
606 LOG_ERROR("mmal_port_send_buffer failed (%i)", status);
607 mmal_queue_put_back(connection->pool->queue, buffer);
608 run_again = 0;
609 break;
610 }
611 }
612 }
613
614 /* Loop through all the connections */
615 for (i = 0, j = graph_private->connection_current++;
616 i < graph_private->connection_num; i++, j++)
617 {
618 MMAL_CONNECTION_T *connection =
619 graph_private->connection[j%graph_private->connection_num];
620 int64_t duration = vcos_getmicrosecs64();
621
622 if (connection->flags & MMAL_CONNECTION_FLAG_TUNNELLING)
623 continue; /* Nothing else to do in tunnelling mode */
624 if (connection->flags & MMAL_CONNECTION_FLAG_DIRECT)
625 continue; /* Nothing else to do in direct mode */
626
627 /* Send any queued buffer to the next component.
628 * We also make sure no connection can starve the others by
629 * having a timeout. */
630 while (vcos_getmicrosecs64() - duration < PROCESSING_TIME_MAX &&
631 (buffer = mmal_queue_get(connection->queue)) != NULL)
632 {
633 run_again = 1;
634
635 graph_process_buffer(graph_private, connection, buffer);
636 }
637 }
638
639 return run_again;
640}
641
642/*****************************************************************************/
643static void graph_do_processing_loop(MMAL_COMPONENT_T *component)
644{
645 while (graph_do_processing((MMAL_GRAPH_PRIVATE_T *)component->priv->module));
646}
647
648/*****************************************************************************/
649static MMAL_PORT_T *find_port_from_graph(MMAL_GRAPH_PRIVATE_T *graph, MMAL_PORT_T *port)
650{
651 MMAL_PORT_T **list;
652 unsigned int *list_num;
653
654 switch (port->type)
655 {
656 case MMAL_PORT_TYPE_INPUT:
657 list = graph->input;
658 list_num = &graph->input_num;
659 break;
660 case MMAL_PORT_TYPE_OUTPUT:
661 list = graph->output;
662 list_num = &graph->output_num;
663 break;
664 case MMAL_PORT_TYPE_CLOCK:
665 list = graph->clock;
666 list_num = &graph->clock_num;
667 break;
668 default:
669 return 0;
670 }
671
672 if (port->index > *list_num)
673 return 0;
674
675 return list[port->index];
676}
677
678static MMAL_PORT_T *find_port_to_graph(MMAL_GRAPH_PRIVATE_T *graph, MMAL_PORT_T *port)
679{
680 MMAL_COMPONENT_T *component = graph->graph_component;
681 MMAL_PORT_T **list, **component_list;
682 unsigned int i, *list_num;
683
684 switch (port->type)
685 {
686 case MMAL_PORT_TYPE_INPUT:
687 list = graph->input;
688 list_num = &graph->input_num;
689 component_list = component->input;
690 break;
691 case MMAL_PORT_TYPE_OUTPUT:
692 list = graph->output;
693 list_num = &graph->output_num;
694 component_list = component->output;
695 break;
696 case MMAL_PORT_TYPE_CLOCK:
697 list = graph->clock;
698 list_num = &graph->clock_num;
699 component_list = component->clock;
700 break;
701 default:
702 return 0;
703 }
704
705 for (i = 0; i < *list_num; i++)
706 if (list[i] == port)
707 break;
708
709 if (i == *list_num)
710 return 0;
711 return component_list[i];
712}
713
714static MMAL_STATUS_T graph_port_update(MMAL_GRAPH_PRIVATE_T *graph,
715 MMAL_PORT_T *graph_port, MMAL_BOOL_T init)
716{
717 MMAL_STATUS_T status;
718 MMAL_PORT_T *port;
719
720 port = find_port_from_graph(graph, graph_port);
721 if (!port)
722 {
723 LOG_ERROR("could not find matching port for %p", graph_port);
724 return MMAL_EINVAL;
725 }
726
727 status = mmal_format_full_copy(graph_port->format, port->format);
728 if (status != MMAL_SUCCESS)
729 {
730 LOG_ERROR("format copy failed on port %s", port->name);
731 return status;
732 }
733
734 graph_port->buffer_num_min = port->buffer_num_min;
735 graph_port->buffer_num_recommended = port->buffer_num_recommended;
736 graph_port->buffer_size_min = port->buffer_size_min;
737 graph_port->buffer_size_recommended = port->buffer_size_recommended;
738 graph_port->buffer_alignment_min = port->buffer_alignment_min;
739 graph_port->capabilities = port->capabilities;
740 if (init)
741 {
742 graph_port->buffer_num = port->buffer_num;
743 graph_port->buffer_size = port->buffer_size;
744 }
745 return MMAL_SUCCESS;
746}
747
748static MMAL_STATUS_T graph_port_update_requirements(MMAL_GRAPH_PRIVATE_T *graph,
749 MMAL_PORT_T *graph_port)
750{
751 MMAL_PORT_T *port;
752
753 port = find_port_from_graph(graph, graph_port);
754 if (!port)
755 {
756 LOG_ERROR("could not find matching port for %p", graph_port);
757 return MMAL_EINVAL;
758 }
759
760 graph_port->buffer_num_min = port->buffer_num_min;
761 graph_port->buffer_num_recommended = port->buffer_num_recommended;
762 graph_port->buffer_size_min = port->buffer_size_min;
763 graph_port->buffer_size_recommended = port->buffer_size_recommended;
764 graph_port->buffer_alignment_min = port->buffer_alignment_min;
765 return MMAL_SUCCESS;
766}
767
768/** Destroy a previously created component */
769static MMAL_STATUS_T graph_component_destroy(MMAL_COMPONENT_T *component)
770{
771 MMAL_COMPONENT_MODULE_T *graph = component->priv->module;
772
773 /* Notify client of destruction */
774 if (graph->graph.pf_destroy)
775 graph->graph.pf_destroy(&graph->graph);
776 graph->graph.pf_destroy = NULL;
777
778 if (component->input_num)
779 mmal_ports_free(component->input, component->input_num);
780
781 if (component->output_num)
782 mmal_ports_free(component->output, component->output_num);
783
784 if (component->clock_num)
785 mmal_ports_clock_free(component->clock, component->clock_num);
786
787 /* coverity[address_free] Freeing the first item in the structure is safe */
788 mmal_graph_destroy(&graph->graph);
789 return MMAL_SUCCESS;
790}
791
792/** Enable processing on a component */
793static MMAL_STATUS_T graph_component_enable(MMAL_COMPONENT_T *component)
794{
795 MMAL_GRAPH_PRIVATE_T *graph_private = component->priv->module;
796 MMAL_STATUS_T status = MMAL_ENOSYS;
797
798 /* Call user defined function first */
799 if (graph_private->graph.pf_graph_enable)
800 status = graph_private->graph.pf_graph_enable(&graph_private->graph, MMAL_TRUE);
801
802 return status;
803}
804
805/** Disable processing on a component */
806static MMAL_STATUS_T graph_component_disable(MMAL_COMPONENT_T *component)
807{
808 MMAL_GRAPH_PRIVATE_T *graph_private = component->priv->module;
809 MMAL_STATUS_T status = MMAL_ENOSYS;
810
811 /* Call user defined function first */
812 if (graph_private->graph.pf_graph_enable)
813 status = graph_private->graph.pf_graph_enable(&graph_private->graph, MMAL_FALSE);
814
815 return status;
816}
817
818/** Callback given to mmal_port_enable() */
819static void graph_port_enable_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
820{
821 MMAL_GRAPH_PRIVATE_T *graph_private = (MMAL_GRAPH_PRIVATE_T *)port->userdata;
822 MMAL_PORT_T *graph_port;
823 MMAL_STATUS_T status;
824
825 graph_port = find_port_to_graph(graph_private, port);
826 if (!graph_port)
827 {
828 vcos_assert(0);
829 mmal_buffer_header_release(buffer);
830 return;
831 }
832
833 /* Call user defined function first */
834 if (graph_private->graph.pf_return_buffer)
835 {
836 status = graph_private->graph.pf_return_buffer(&graph_private->graph, graph_port, buffer);
837 if (status != MMAL_ENOSYS)
838 return;
839 }
840
841 /* Forward the callback */
842 if (buffer->cmd)
843 mmal_port_event_send(graph_port, buffer);
844 else
845 mmal_port_buffer_header_callback(graph_port, buffer);
846}
847
848/** Check whether 2 ports of a component are linked */
849static MMAL_BOOL_T graph_component_topology_ports_linked(MMAL_GRAPH_PRIVATE_T *graph,
850 MMAL_PORT_T *port1, MMAL_PORT_T *port2)
851{
852 MMAL_COMPONENT_T *component = port1->component;
853 unsigned int i;
854
855 for (i = 0; i < graph->component_num; i++)
856 if (component == graph->component[i])
857 break;
858
859 if (i == graph->component_num)
860 return MMAL_FALSE; /* Component not found */
861
862 if (graph->topology[i] == MMAL_GRAPH_TOPOLOGY_STRAIGHT)
863 return port1->index == port2->index;
864
865 return MMAL_TRUE;
866}
867
868/** Propagate a port enable */
869static MMAL_STATUS_T graph_port_state_propagate(MMAL_GRAPH_PRIVATE_T *graph,
870 MMAL_PORT_T *port, MMAL_BOOL_T enable)
871{
872 MMAL_COMPONENT_T *component = port->component;
873 MMAL_STATUS_T status = MMAL_SUCCESS;
874 MMAL_PORT_TYPE_T type = port->type;
875 unsigned int i, j;
876
877 LOG_TRACE("graph: %p, port %s(%p)", graph, port->name, port);
878
879 if (port->type == MMAL_PORT_TYPE_OUTPUT)
880 type = MMAL_PORT_TYPE_INPUT;
881 if (port->type == MMAL_PORT_TYPE_INPUT)
882 type = MMAL_PORT_TYPE_OUTPUT;
883
884 /* Loop through all the output ports of the component and if they are not enabled and
885 * match one of the connections we maintain, then we need to propagate the port enable. */
886 for (i = 0; i < component->port_num; i++)
887 {
888 if (component->port[i]->type != type)
889 continue;
890
891 if ((component->port[i]->is_enabled && enable) ||
892 (!component->port[i]->is_enabled && !enable))
893 continue;
894
895 /* Find the matching connection */
896 for (j = 0; j < graph->connection_num; j++)
897 if (graph->connection[j]->out == component->port[i] ||
898 graph->connection[j]->in == component->port[i])
899 break;
900
901 if (j == graph->connection_num)
902 continue; /* No match */
903
904 if (!graph_component_topology_ports_linked(graph, port, component->port[i]))
905 continue; /* Ports are independent */
906
907 if (enable)
908 {
909 status = mmal_connection_enable(graph->connection[j]);
910 if (status != MMAL_SUCCESS)
911 break;
912
913 mmal_log_dump_port(graph->connection[j]->out);
914 mmal_log_dump_port(graph->connection[j]->in);
915 }
916
917 status = graph_port_state_propagate(graph, graph->connection[j]->in == component->port[i] ?
918 graph->connection[j]->out : graph->connection[j]->in, enable);
919 if (status != MMAL_SUCCESS)
920 break;
921
922 if (!enable)
923 {
924 status = mmal_connection_disable(graph->connection[j]);
925 if (status != MMAL_SUCCESS)
926 break;
927 }
928 }
929
930 return status;
931}
932
933/** Enable processing on a port */
934static MMAL_STATUS_T graph_port_enable(MMAL_PORT_T *graph_port, MMAL_PORT_BH_CB_T cb)
935{
936 MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
937 MMAL_PORT_T *port;
938 MMAL_STATUS_T status;
939 MMAL_PARAM_UNUSED(cb);
940
941 port = find_port_from_graph(graph_private, graph_port);
942 if (!port)
943 return MMAL_EINVAL;
944
945 /* Update the buffer requirements */
946 port->buffer_num = graph_port->buffer_num;
947 port->buffer_size = graph_port->buffer_size;
948
949 /* Call user defined function first */
950 if (graph_private->graph.pf_enable)
951 {
952 status = graph_private->graph.pf_enable(&graph_private->graph, graph_port);
953 if (status != MMAL_ENOSYS)
954 return status;
955 }
956
957 /* We'll intercept the callback */
958 port->userdata = (void *)graph_private;
959 status = mmal_port_enable(port, graph_port_enable_cb);
960 if (status != MMAL_SUCCESS)
961 return status;
962
963 /* We need to enable all the connected connections */
964 status = graph_port_state_propagate(graph_private, port, 1);
965
966 mmal_component_action_trigger(graph_port->component);
967 return status;
968}
969
970/** Disable processing on a port */
971static MMAL_STATUS_T graph_port_disable(MMAL_PORT_T *graph_port)
972{
973 MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
974 MMAL_STATUS_T status;
975 MMAL_PORT_T *port;
976
977 port = find_port_from_graph(graph_port->component->priv->module, graph_port);
978 if (!port)
979 return MMAL_EINVAL;
980
981 /* Call user defined function first */
982 if (graph_private->graph.pf_disable)
983 {
984 status = graph_private->graph.pf_disable(&graph_private->graph, graph_port);
985 if (status != MMAL_ENOSYS)
986 return status;
987 }
988
989 /* We need to disable all the connected connections.
990 * Since disable does an implicit flush, we only want to do that if
991 * we're acting on an input port or we risk discarding buffers along
992 * the way. */
993 if (!graph_private->input_num || port->type == MMAL_PORT_TYPE_INPUT)
994 {
995 MMAL_STATUS_T status = graph_port_state_propagate(graph_private, port, 0);
996 if (status != MMAL_SUCCESS)
997 return status;
998 }
999
1000 /* Forward the call */
1001 return mmal_port_disable(port);
1002}
1003
1004/** Propagate a port flush */
1005static MMAL_STATUS_T graph_port_flush_propagate(MMAL_GRAPH_PRIVATE_T *graph,
1006 MMAL_PORT_T *port)
1007{
1008 MMAL_COMPONENT_T *component = port->component;
1009 MMAL_STATUS_T status;
1010 unsigned int i, j;
1011
1012 LOG_TRACE("graph: %p, port %s(%p)", graph, port->name, port);
1013
1014 status = mmal_port_flush(port);
1015 if (status != MMAL_SUCCESS)
1016 return status;
1017
1018 if (port->type == MMAL_PORT_TYPE_OUTPUT)
1019 return MMAL_SUCCESS;
1020
1021 /* Loop through all the output ports of the component and if they match one
1022 * of the connections we maintain, then we need to propagate the flush. */
1023 for (i = 0; i < component->port_num; i++)
1024 {
1025 if (component->port[i]->type != MMAL_PORT_TYPE_OUTPUT)
1026 continue;
1027 if (!component->port[i]->is_enabled)
1028 continue;
1029
1030 /* Find the matching connection */
1031 for (j = 0; j < graph->connection_num; j++)
1032 if (graph->connection[j]->out == component->port[i])
1033 break;
1034
1035 if (j == graph->connection_num)
1036 continue; /* No match */
1037
1038 if (!graph_component_topology_ports_linked(graph, port, component->port[i]))
1039 continue; /* Ports are independent */
1040
1041 /* Flush any buffer waiting in the connection queue */
1042 if (graph->connection[j]->queue)
1043 {
1044 MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(graph->connection[j]->queue);
1045 while(buffer)
1046 {
1047 mmal_buffer_header_release(buffer);
1048 buffer = mmal_queue_get(graph->connection[j]->queue);
1049 }
1050 }
1051
1052 status = graph_port_flush_propagate(graph, graph->connection[j]->in);
1053 if (status != MMAL_SUCCESS)
1054 break;
1055 }
1056
1057 return status;
1058}
1059
1060/** Flush a port */
1061static MMAL_STATUS_T graph_port_flush(MMAL_PORT_T *graph_port)
1062{
1063 MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
1064 MMAL_STATUS_T status;
1065 MMAL_PORT_T *port;
1066
1067 port = find_port_from_graph(graph_private, graph_port);
1068 if (!port)
1069 return MMAL_EINVAL;
1070
1071 /* Call user defined function first */
1072 if (graph_private->graph.pf_flush)
1073 {
1074 status = graph_private->graph.pf_flush(&graph_private->graph, graph_port);
1075 if (status != MMAL_ENOSYS)
1076 return status;
1077 }
1078
1079 /* Forward the call */
1080 return graph_port_flush_propagate(graph_private, port);
1081}
1082
1083/** Send a buffer header to a port */
1084static MMAL_STATUS_T graph_port_send(MMAL_PORT_T *graph_port, MMAL_BUFFER_HEADER_T *buffer)
1085{
1086 MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
1087 MMAL_STATUS_T status;
1088 MMAL_PORT_T *port;
1089
1090 port = find_port_from_graph(graph_port->component->priv->module, graph_port);
1091 if (!port)
1092 return MMAL_EINVAL;
1093
1094 /* Call user defined function first */
1095 if (graph_private->graph.pf_send_buffer)
1096 {
1097 status = graph_private->graph.pf_send_buffer(&graph_private->graph, graph_port, buffer);
1098 if (status != MMAL_ENOSYS)
1099 return status;
1100 }
1101
1102 /* Forward the call */
1103 return mmal_port_send_buffer(port, buffer);
1104}
1105
1106/** Propagate a format change */
1107static MMAL_STATUS_T graph_port_format_commit_propagate(MMAL_GRAPH_PRIVATE_T *graph,
1108 MMAL_PORT_T *port)
1109{
1110 MMAL_COMPONENT_T *component = port->component;
1111 MMAL_STATUS_T status = MMAL_SUCCESS;
1112 unsigned int i, j;
1113
1114 LOG_TRACE("graph: %p, port %s(%p)", graph, port->name, port);
1115
1116 if (port->type == MMAL_PORT_TYPE_OUTPUT || port->type == MMAL_PORT_TYPE_CLOCK)
1117 return MMAL_SUCCESS; /* Nothing to do */
1118
1119 /* Loop through all the output ports of the component and if they are not enabled and
1120 * match one of the connections we maintain, then we need to propagate the format change. */
1121 for (i = 0; i < component->output_num; i++)
1122 {
1123 MMAL_PORT_T *in, *out;
1124
1125 if (component->output[i]->is_enabled)
1126 continue;
1127
1128 /* Find the matching connection */
1129 for (j = 0; j < graph->connection_num; j++)
1130 if (graph->connection[j]->out == component->output[i])
1131 break;
1132
1133 if (j == graph->connection_num)
1134 continue; /* No match */
1135
1136 if (!graph_component_topology_ports_linked(graph, port, component->output[i]))
1137 continue; /* Ports are independent */
1138
1139 in = graph->connection[j]->in;
1140 out = graph->connection[j]->out;
1141
1142 /* Apply the format to the input port */
1143 status = mmal_format_full_copy(in->format, out->format);
1144 if (status != MMAL_SUCCESS)
1145 break;
1146 status = mmal_port_format_commit(in);
1147 if (status != MMAL_SUCCESS)
1148 break;
1149
1150 mmal_log_dump_port(out);
1151 mmal_log_dump_port(in);
1152
1153 status = graph_port_format_commit_propagate(graph, in);
1154 if (status != MMAL_SUCCESS)
1155 break;
1156 }
1157
1158 return status;
1159}
1160
1161/** Set format on a port */
1162static MMAL_STATUS_T graph_port_format_commit(MMAL_PORT_T *graph_port)
1163{
1164 MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
1165 MMAL_STATUS_T status;
1166 MMAL_PORT_T *port;
1167 unsigned int i;
1168
1169 /* Call user defined function first */
1170 if (graph_private->graph.pf_format_commit)
1171 {
1172 status = graph_private->graph.pf_format_commit(&graph_private->graph, graph_port);
1173 if (status == MMAL_SUCCESS)
1174 goto end;
1175 if (status != MMAL_ENOSYS)
1176 return status;
1177 }
1178
1179 port = find_port_from_graph(graph_private, graph_port);
1180 if (!port)
1181 return MMAL_EINVAL;
1182
1183 /* Update actual port */
1184 status = mmal_format_full_copy(port->format, graph_port->format);
1185 if (status != MMAL_SUCCESS)
1186 return status;
1187 port->buffer_num = graph_port->buffer_num;
1188 port->buffer_size = graph_port->buffer_size;
1189
1190 /* Forward the call */
1191 status = mmal_port_format_commit(port);
1192 if (status != MMAL_SUCCESS)
1193 return status;
1194
1195 /* Propagate format changes to the connections */
1196 status = graph_port_format_commit_propagate(graph_private, port);
1197 if (status != MMAL_SUCCESS)
1198 {
1199 LOG_ERROR("couldn't propagate format commit of port %s(%p)", port->name, port);
1200 return status;
1201 }
1202
1203 end:
1204 /* Read the values back */
1205 status = graph_port_update(graph_private, graph_port, MMAL_FALSE);
1206 if (status != MMAL_SUCCESS)
1207 return status;
1208
1209 /* Get the settings for the output ports in case they have changed */
1210 if (graph_port->type == MMAL_PORT_TYPE_INPUT)
1211 {
1212 for (i = 0; i < graph_private->output_num; i++)
1213 {
1214 status = graph_port_update(graph_private, graph_port->component->output[i], MMAL_FALSE);
1215 if (status != MMAL_SUCCESS)
1216 return status;
1217 }
1218 }
1219
1220 return MMAL_SUCCESS;
1221}
1222
1223static MMAL_STATUS_T graph_port_control_parameter_get(MMAL_PORT_T *graph_port,
1224 MMAL_PARAMETER_HEADER_T *param)
1225{
1226 MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
1227 MMAL_STATUS_T status = MMAL_ENOSYS;
1228 unsigned int i;
1229
1230 /* Call user defined function first */
1231 if (graph_private->graph.pf_parameter_get)
1232 {
1233 status = graph_private->graph.pf_parameter_get(&graph_private->graph, graph_port, param);
1234 if (status != MMAL_ENOSYS)
1235 return status;
1236 }
1237
1238 /* By default we do a get parameter on each component until one succeeds */
1239 for (i = 0; i < graph_private->component_num && status != MMAL_SUCCESS; i++)
1240 status = mmal_port_parameter_get(graph_private->component[i]->control, param);
1241
1242 return status;
1243}
1244
1245static MMAL_STATUS_T graph_port_parameter_get(MMAL_PORT_T *graph_port,
1246 MMAL_PARAMETER_HEADER_T *param)
1247{
1248 MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
1249 MMAL_STATUS_T status;
1250 MMAL_PORT_T *port;
1251
1252 /* Call user defined function first */
1253 if (graph_private->graph.pf_parameter_get)
1254 {
1255 status = graph_private->graph.pf_parameter_get(&graph_private->graph, graph_port, param);
1256 if (status != MMAL_ENOSYS)
1257 return status;
1258 }
1259
1260 port = find_port_from_graph(graph_private, graph_port);
1261 if (!port)
1262 return MMAL_EINVAL;
1263
1264 /* Forward the call */
1265 return mmal_port_parameter_get(port, param);
1266}
1267
1268static MMAL_STATUS_T graph_port_control_parameter_set(MMAL_PORT_T *graph_port,
1269 const MMAL_PARAMETER_HEADER_T *param)
1270{
1271 MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
1272 MMAL_STATUS_T status = MMAL_ENOSYS;
1273 unsigned int i;
1274
1275 /* Call user defined function first */
1276 if (graph_private->graph.pf_parameter_set)
1277 {
1278 status = graph_private->graph.pf_parameter_set(&graph_private->graph, graph_port, param);
1279 if (status != MMAL_ENOSYS)
1280 return status;
1281 }
1282
1283 /* By default we do a set parameter on each component until one succeeds */
1284 for (i = 0; i < graph_private->component_num && status != MMAL_SUCCESS; i++)
1285 status = mmal_port_parameter_set(graph_private->component[i]->control, param);
1286
1287 return status;
1288}
1289
1290static MMAL_STATUS_T graph_port_parameter_set(MMAL_PORT_T *graph_port,
1291 const MMAL_PARAMETER_HEADER_T *param)
1292{
1293 MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
1294 MMAL_STATUS_T status;
1295 MMAL_PORT_T *port;
1296
1297 /* Call user defined function first */
1298 if (graph_private->graph.pf_parameter_set)
1299 {
1300 status = graph_private->graph.pf_parameter_set(&graph_private->graph, graph_port, param);
1301 if (status != MMAL_ENOSYS)
1302 return status;
1303 }
1304
1305 port = find_port_from_graph(graph_private, graph_port);
1306 if (!port)
1307 return MMAL_EINVAL;
1308
1309 /* Forward the call */
1310 status = mmal_port_parameter_set(port, param);
1311 if (status != MMAL_SUCCESS)
1312 goto end;
1313
1314 if (param->id == MMAL_PARAMETER_BUFFER_REQUIREMENTS)
1315 {
1316 /* This might have changed the buffer requirements of other ports so fetch them all */
1317 MMAL_COMPONENT_T *component = graph_port->component;
1318 unsigned int i;
1319 for (i = 0; status == MMAL_SUCCESS && i < component->input_num; i++)
1320 status = graph_port_update_requirements(graph_private, component->input[i]);
1321 for (i = 0; status == MMAL_SUCCESS && i < component->output_num; i++)
1322 status = graph_port_update_requirements(graph_private, component->output[i]);
1323 }
1324
1325 end:
1326 return status;
1327}
1328
1329static MMAL_STATUS_T graph_port_connect(MMAL_PORT_T *graph_port, MMAL_PORT_T *other_port)
1330{
1331 MMAL_PORT_T *port;
1332
1333 LOG_TRACE("%s(%p) %s(%p)", graph_port->name, graph_port, other_port->name, other_port);
1334
1335 port = find_port_from_graph(graph_port->component->priv->module, graph_port);
1336 if (!port)
1337 return MMAL_EINVAL;
1338
1339 /* Forward the call */
1340 return other_port ? mmal_port_connect(port, other_port) : mmal_port_disconnect(port);
1341}
1342
1343static uint8_t *graph_port_payload_alloc(MMAL_PORT_T *graph_port, uint32_t payload_size)
1344{
1345 MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
1346 MMAL_STATUS_T status;
1347 MMAL_PORT_T *port;
1348 uint8_t *payload;
1349
1350 port = find_port_from_graph(graph_port->component->priv->module, graph_port);
1351 if (!port)
1352 return 0;
1353
1354 /* Call user defined function first */
1355 if (graph_private->graph.pf_payload_alloc)
1356 {
1357 status = graph_private->graph.pf_payload_alloc(&graph_private->graph, graph_port,
1358 payload_size, &payload);
1359 if (status != MMAL_ENOSYS)
1360 return status == MMAL_SUCCESS ? payload : NULL;
1361 }
1362
1363 /* Forward the call */
1364 return mmal_port_payload_alloc(port, payload_size);
1365}
1366
1367static void graph_port_payload_free(MMAL_PORT_T *graph_port, uint8_t *payload)
1368{
1369 MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
1370 MMAL_STATUS_T status;
1371 MMAL_PORT_T *port;
1372
1373 port = find_port_from_graph(graph_port->component->priv->module, graph_port);
1374 if (!port)
1375 return;
1376
1377 /* Call user defined function first */
1378 if (graph_private->graph.pf_payload_free)
1379 {
1380 status = graph_private->graph.pf_payload_free(&graph_private->graph, graph_port, payload);
1381 if (status == MMAL_SUCCESS)
1382 return;
1383 }
1384
1385 /* Forward the call */
1386 mmal_port_payload_free(port, payload);
1387}
1388
1389/** Create an instance of a component */
1390static MMAL_STATUS_T mmal_component_create_from_graph(const char *name, MMAL_COMPONENT_T *component)
1391{
1392 MMAL_STATUS_T status = MMAL_ENOMEM;
1393 /* Our context is already allocated and available */
1394 MMAL_GRAPH_PRIVATE_T *graph = component->priv->module;
1395 unsigned int i;
1396 MMAL_PARAM_UNUSED(name);
1397
1398 component->control->priv->pf_parameter_get = graph_port_control_parameter_get;
1399 component->control->priv->pf_parameter_set = graph_port_control_parameter_set;
1400
1401 /* Allocate the ports for this component */
1402 if(graph->input_num)
1403 {
1404 component->input = mmal_ports_alloc(component, graph->input_num, MMAL_PORT_TYPE_INPUT, 0);
1405 if(!component->input)
1406 goto error;
1407 }
1408 component->input_num = graph->input_num;
1409 for(i = 0; i < component->input_num; i++)
1410 {
1411 component->input[i]->priv->pf_enable = graph_port_enable;
1412 component->input[i]->priv->pf_disable = graph_port_disable;
1413 component->input[i]->priv->pf_flush = graph_port_flush;
1414 component->input[i]->priv->pf_send = graph_port_send;
1415 component->input[i]->priv->pf_set_format = graph_port_format_commit;
1416 component->input[i]->priv->pf_parameter_get = graph_port_parameter_get;
1417 component->input[i]->priv->pf_parameter_set = graph_port_parameter_set;
1418 if (graph->input[i]->priv->pf_connect && 0 /* FIXME: disabled for now */)
1419 component->input[i]->priv->pf_connect = graph_port_connect;
1420 component->input[i]->priv->pf_payload_alloc = graph_port_payload_alloc;
1421 component->input[i]->priv->pf_payload_free = graph_port_payload_free;
1422
1423 /* Mirror the port values */
1424 status = graph_port_update(graph, component->input[i], MMAL_TRUE);
1425 if (status != MMAL_SUCCESS)
1426 goto error;
1427 }
1428 if(graph->output_num)
1429 {
1430 component->output = mmal_ports_alloc(component, graph->output_num, MMAL_PORT_TYPE_OUTPUT, 0);
1431 if(!component->output)
1432 goto error;
1433 }
1434 component->output_num = graph->output_num;
1435 for(i = 0; i < component->output_num; i++)
1436 {
1437 component->output[i]->priv->pf_enable = graph_port_enable;
1438 component->output[i]->priv->pf_disable = graph_port_disable;
1439 component->output[i]->priv->pf_flush = graph_port_flush;
1440 component->output[i]->priv->pf_send = graph_port_send;
1441 component->output[i]->priv->pf_set_format = graph_port_format_commit;
1442 component->output[i]->priv->pf_parameter_get = graph_port_parameter_get;
1443 component->output[i]->priv->pf_parameter_set = graph_port_parameter_set;
1444 if (graph->output[i]->priv->pf_connect && 0 /* FIXME: disabled for now */)
1445 component->output[i]->priv->pf_connect = graph_port_connect;
1446 component->output[i]->priv->pf_payload_alloc = graph_port_payload_alloc;
1447 component->output[i]->priv->pf_payload_free = graph_port_payload_free;
1448
1449 /* Mirror the port values */
1450 status = graph_port_update(graph, component->output[i], MMAL_TRUE);
1451 if (status != MMAL_SUCCESS)
1452 goto error;
1453 }
1454 if(graph->clock_num)
1455 {
1456 component->clock = mmal_ports_clock_alloc(component, graph->clock_num, 0, NULL);
1457 if(!component->clock)
1458 {
1459 status = MMAL_ENOMEM;
1460 goto error;
1461 }
1462 }
1463 component->clock_num = graph->clock_num;
1464 for(i = 0; i < component->clock_num; i++)
1465 {
1466 component->clock[i]->priv->pf_enable = graph_port_enable;
1467 component->clock[i]->priv->pf_disable = graph_port_disable;
1468 component->clock[i]->priv->pf_flush = graph_port_flush;
1469 component->clock[i]->priv->pf_send = graph_port_send;
1470 component->clock[i]->priv->pf_set_format = graph_port_format_commit;
1471 component->clock[i]->priv->pf_parameter_get = graph_port_parameter_get;
1472 component->clock[i]->priv->pf_parameter_set = graph_port_parameter_set;
1473 component->clock[i]->priv->pf_connect = NULL; /* FIXME: disabled for now */
1474 component->clock[i]->priv->pf_payload_alloc = graph_port_payload_alloc;
1475 component->clock[i]->priv->pf_payload_free = graph_port_payload_free;
1476
1477 /* Mirror the port values */
1478 status = graph_port_update(graph, component->clock[i], MMAL_TRUE);
1479 if (status != MMAL_SUCCESS)
1480 goto error;
1481 }
1482
1483 status = mmal_component_action_register(component, graph_do_processing_loop);
1484 if (status != MMAL_SUCCESS)
1485 goto error;
1486
1487#if 1 // FIXME
1488 /* Set our connection callback */
1489 for (i = 0; i < graph->connection_num; i++)
1490 {
1491 graph->connection[i]->callback = graph_component_connection_cb;
1492 graph->connection[i]->user_data = (void *)component;
1493 }
1494#endif
1495
1496 component->priv->pf_destroy = graph_component_destroy;
1497 component->priv->pf_enable = graph_component_enable;
1498 component->priv->pf_disable = graph_component_disable;
1499 graph->graph_component = component;
1500
1501 /* Enable all the control ports */
1502 for (i = 0; i < graph->component_num; i++)
1503 {
1504 graph->component[i]->control->userdata = (void *)component;
1505 status = mmal_port_enable(graph->component[i]->control, graph_component_control_cb);
1506 if (status != MMAL_SUCCESS)
1507 LOG_ERROR("could not enable port %s", component->control->name);
1508 }
1509
1510 return MMAL_SUCCESS;
1511
1512 error:
1513 graph_component_destroy(component);
1514 return status;
1515}
1516
1517MMAL_PORT_T *mmal_graph_find_port(MMAL_GRAPH_T *graph,
1518 const char *name,
1519 MMAL_PORT_TYPE_T type,
1520 unsigned index)
1521{
1522 unsigned i;
1523 MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
1524 for (i=0; i<private->component_num; i++)
1525 {
1526 MMAL_COMPONENT_T *comp = private->component[i];
1527 if (vcos_strcasecmp(name, comp->name) == 0)
1528 {
1529 unsigned num;
1530 MMAL_PORT_T **ports;
1531 if (type == MMAL_PORT_TYPE_INPUT) {
1532 num = comp->input_num;
1533 ports = comp->input;
1534 }
1535 else if (type == MMAL_PORT_TYPE_OUTPUT) {
1536 num = comp->output_num;
1537 ports = comp->output;
1538 }
1539 else if (type == MMAL_PORT_TYPE_CLOCK) {
1540 num = comp->clock_num;
1541 ports = comp->clock;
1542 }
1543 else if (type == MMAL_PORT_TYPE_CONTROL) {
1544 num = 1;
1545 ports = &comp->control;
1546 }
1547 else {
1548 vcos_assert(0);
1549 return NULL;
1550 }
1551 if (index < num)
1552 {
1553 /* coverity[ptr_arith] num is 1 at this point */
1554 return ports[index];
1555 }
1556 }
1557 }
1558 LOG_INFO("port %s:%d not found", name, index);
1559 return NULL;
1560}
1561