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 | #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 */ |
42 | typedef 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 | |
72 | typedef MMAL_GRAPH_PRIVATE_T MMAL_COMPONENT_MODULE_T; |
73 | |
74 | /*****************************************************************************/ |
75 | static MMAL_STATUS_T mmal_component_create_from_graph(const char *name, MMAL_COMPONENT_T *component); |
76 | static MMAL_BOOL_T graph_do_processing(MMAL_GRAPH_PRIVATE_T *graph); |
77 | static void graph_process_buffer(MMAL_GRAPH_PRIVATE_T *graph_private, |
78 | MMAL_CONNECTION_T *connection, MMAL_BUFFER_HEADER_T *buffer); |
79 | |
80 | /*****************************************************************************/ |
81 | static 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 | /*****************************************************************************/ |
101 | static 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 | /*****************************************************************************/ |
117 | static 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 | /*****************************************************************************/ |
135 | static 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 | /*****************************************************************************/ |
143 | MMAL_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 | /*****************************************************************************/ |
171 | MMAL_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 | /*****************************************************************************/ |
198 | MMAL_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 | /*****************************************************************************/ |
220 | MMAL_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 | /*****************************************************************************/ |
250 | MMAL_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 | /*****************************************************************************/ |
271 | MMAL_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 | /*****************************************************************************/ |
311 | MMAL_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 | /*****************************************************************************/ |
344 | MMAL_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 | /*****************************************************************************/ |
383 | MMAL_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 | /*****************************************************************************/ |
433 | MMAL_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 | /*****************************************************************************/ |
455 | MMAL_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 | /*****************************************************************************/ |
464 | MMAL_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 | /*****************************************************************************/ |
472 | static 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 | /*****************************************************************************/ |
494 | static 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 | /*****************************************************************************/ |
511 | static 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 | /*****************************************************************************/ |
547 | static 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 | /*****************************************************************************/ |
579 | static 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 | /*****************************************************************************/ |
643 | static 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 | /*****************************************************************************/ |
649 | static 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 | |
678 | static 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 | |
714 | static 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 | |
748 | static 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 */ |
769 | static 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 */ |
793 | static 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 */ |
806 | static 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() */ |
819 | static 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 */ |
849 | static 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 */ |
869 | static 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 */ |
934 | static 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 */ |
971 | static 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 */ |
1005 | static 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 */ |
1061 | static 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 */ |
1084 | static 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 */ |
1107 | static 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 */ |
1162 | static 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 | |
1223 | static 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 | |
1245 | static 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 | |
1268 | static 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 | |
1290 | static 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 | |
1329 | static 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 | |
1343 | static 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 | |
1367 | static 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 */ |
1390 | static 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 | |
1517 | MMAL_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 | |