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 "core/mmal_component_private.h"
30#include "core/mmal_port_private.h"
31#include "mmal_logging.h"
32
33#define PASSTHROUGH_PORTS_NUM 1
34
35/*****************************************************************************/
36typedef struct MMAL_COMPONENT_MODULE_T
37{
38 MMAL_BOOL_T error; /**< Error state */
39
40} MMAL_COMPONENT_MODULE_T;
41
42typedef struct MMAL_PORT_MODULE_T
43{
44 MMAL_QUEUE_T *queue; /**< queue for the buffers sent to the ports */
45
46} MMAL_PORT_MODULE_T;
47
48/*****************************************************************************/
49
50/** Destroy a previously created component */
51static MMAL_STATUS_T passthrough_component_destroy(MMAL_COMPONENT_T *component)
52{
53 unsigned int i;
54
55 for(i = 0; i < component->input_num; i++)
56 if(component->input[i]->priv->module->queue)
57 mmal_queue_destroy(component->input[i]->priv->module->queue);
58 if(component->input_num)
59 mmal_ports_free(component->input, component->input_num);
60
61 for(i = 0; i < component->output_num; i++)
62 if(component->output[i]->priv->module->queue)
63 mmal_queue_destroy(component->output[i]->priv->module->queue);
64 if(component->output_num)
65 mmal_ports_free(component->output, component->output_num);
66
67 vcos_free(component->priv->module);
68 return MMAL_SUCCESS;
69}
70
71/** Enable processing on a port */
72static MMAL_STATUS_T passthrough_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
73{
74 MMAL_PARAM_UNUSED(port);
75 MMAL_PARAM_UNUSED(cb);
76 return MMAL_SUCCESS;
77}
78
79/** Flush a port */
80static MMAL_STATUS_T passthrough_port_flush(MMAL_PORT_T *port)
81{
82 MMAL_PORT_MODULE_T *port_module = port->priv->module;
83 MMAL_BUFFER_HEADER_T *buffer;
84
85 /* Flush buffers that our component is holding on to */
86 buffer = mmal_queue_get(port_module->queue);
87 while(buffer)
88 {
89 mmal_port_buffer_header_callback(port, buffer);
90 buffer = mmal_queue_get(port_module->queue);
91 }
92
93 return MMAL_SUCCESS;
94}
95
96/** Disable processing on a port */
97static MMAL_STATUS_T passthrough_port_disable(MMAL_PORT_T *port)
98{
99 /* We just need to flush our internal queue */
100 return passthrough_port_flush(port);
101}
102
103/** Send a buffer header to a port */
104static MMAL_STATUS_T passthrough_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
105{
106 MMAL_COMPONENT_T *component = port->component;
107 MMAL_COMPONENT_MODULE_T *module = component->priv->module;
108 MMAL_PORT_T **other_port, *in_port, *out_port;
109 MMAL_BUFFER_HEADER_T **other_buffer, *in = 0, *out = 0;
110 MMAL_STATUS_T status;
111
112 if (module->error)
113 {
114 mmal_queue_put(port->priv->module->queue, buffer);
115 return MMAL_SUCCESS; /* Just do nothing */
116 }
117
118 in_port = port->component->input[port->index];
119 out_port = port->component->output[port->index];
120
121 if (port->type == MMAL_PORT_TYPE_INPUT)
122 {
123 other_port = &out_port;
124 other_buffer = &out;
125 in = buffer;
126 }
127 else
128 {
129 other_port = &in_port;
130 other_buffer = &in;
131 out = buffer;
132 }
133
134 /* Get a buffer header from the matching port */
135 *other_buffer = mmal_queue_get((*other_port)->priv->module->queue);
136 if (!*other_buffer)
137 {
138 /* None available. Just queue the buffer header for now. */
139 mmal_queue_put(port->priv->module->queue, buffer);
140 return MMAL_SUCCESS;
141 }
142
143 /* Copy our input buffer header */
144 status = mmal_buffer_header_replicate(out, in);
145 if (status != MMAL_SUCCESS)
146 goto error;
147
148 /* Consume the input buffer */
149 in->length = 0;
150
151 /* Send buffers back */
152 mmal_port_buffer_header_callback(in_port, in);
153 mmal_port_buffer_header_callback(out_port, out);
154
155 return MMAL_SUCCESS;
156
157 error:
158 mmal_queue_put(in_port->priv->module->queue, in);
159 mmal_queue_put(out_port->priv->module->queue, out);
160 status = mmal_event_error_send(port->component, status);
161 if (status != MMAL_SUCCESS)
162 {
163 LOG_ERROR("unable to send an error event buffer (%i)", (int)status);
164 return MMAL_SUCCESS;
165 }
166 module->error = 1;
167 return MMAL_SUCCESS;
168}
169
170/** Set format on a port */
171static MMAL_STATUS_T passthrough_port_format_commit(MMAL_PORT_T *port)
172{
173 /* Sanity check */
174 if (port->type == MMAL_PORT_TYPE_OUTPUT)
175 {
176 LOG_ERROR("output port is read-only");
177 return MMAL_EINVAL;
178 }
179
180 return mmal_format_full_copy(port->component->output[port->index]->format, port->format);
181}
182
183static MMAL_STATUS_T passthrough_port_parameter_set(MMAL_PORT_T *port, const MMAL_PARAMETER_HEADER_T *param)
184{
185 MMAL_COMPONENT_T *component = port->component;
186 MMAL_PORT_T *in = component->input[port->index], *out = component->input[port->index];
187
188 switch (param->id)
189 {
190 case MMAL_PARAMETER_BUFFER_REQUIREMENTS:
191 {
192 /* Propagate the requirements to the matching input and output the ports */
193 const MMAL_PARAMETER_BUFFER_REQUIREMENTS_T *req = (const MMAL_PARAMETER_BUFFER_REQUIREMENTS_T *)param;
194 uint32_t buffer_num_min = MMAL_MAX(port->buffer_num_min, req->buffer_num_min);
195 uint32_t buffer_num_recommended = MMAL_MAX(port->buffer_num_recommended, req->buffer_num_recommended);
196 uint32_t buffer_size_min = MMAL_MAX(port->buffer_size_min, req->buffer_size_min);
197 uint32_t buffer_size_recommended = MMAL_MAX(port->buffer_size_recommended, req->buffer_size_recommended);
198
199 in->buffer_num_min = buffer_num_min;
200 in->buffer_num_recommended = buffer_num_recommended;
201 in->buffer_size_min = buffer_size_min;
202 in->buffer_size_recommended = buffer_size_recommended;
203 out->buffer_num_min = buffer_num_min;
204 out->buffer_num_recommended = buffer_num_recommended;
205 out->buffer_size_min = buffer_size_min;
206 out->buffer_size_recommended = buffer_size_recommended;
207 }
208 return MMAL_SUCCESS;
209
210 default:
211 return MMAL_ENOSYS;
212 }
213}
214
215/** Create an instance of a component */
216static MMAL_STATUS_T mmal_component_create_passthrough(const char *name, MMAL_COMPONENT_T *component)
217{
218 MMAL_COMPONENT_MODULE_T *module;
219 MMAL_STATUS_T status = MMAL_ENOMEM;
220 unsigned int i;
221 MMAL_PARAM_UNUSED(name);
222
223 /* Allocate the context for our module */
224 component->priv->module = module = vcos_malloc(sizeof(*module), "mmal module");
225 if (!module)
226 return MMAL_ENOMEM;
227 memset(module, 0, sizeof(*module));
228
229 component->priv->pf_destroy = passthrough_component_destroy;
230
231 /* Allocate and initialise all the ports for this component */
232 component->input = mmal_ports_alloc(component, PASSTHROUGH_PORTS_NUM,
233 MMAL_PORT_TYPE_INPUT, sizeof(MMAL_PORT_MODULE_T));
234 if(!component->input)
235 goto error;
236 component->input_num = PASSTHROUGH_PORTS_NUM;
237 for(i = 0; i < component->input_num; i++)
238 {
239 component->input[i]->priv->pf_enable = passthrough_port_enable;
240 component->input[i]->priv->pf_disable = passthrough_port_disable;
241 component->input[i]->priv->pf_flush = passthrough_port_flush;
242 component->input[i]->priv->pf_send = passthrough_port_send;
243 component->input[i]->priv->pf_set_format = passthrough_port_format_commit;
244 component->input[i]->priv->pf_parameter_set = passthrough_port_parameter_set;
245 component->input[i]->buffer_num_min = 1;
246 component->input[i]->buffer_num_recommended = 0;
247 component->input[i]->priv->module->queue = mmal_queue_create();
248 if(!component->input[i]->priv->module->queue)
249 goto error;
250 }
251
252 component->output = mmal_ports_alloc(component, PASSTHROUGH_PORTS_NUM,
253 MMAL_PORT_TYPE_OUTPUT, sizeof(MMAL_PORT_MODULE_T));
254 if(!component->output)
255 goto error;
256 component->output_num = PASSTHROUGH_PORTS_NUM;
257 for(i = 0; i < component->output_num; i++)
258 {
259 component->output[i]->priv->pf_enable = passthrough_port_enable;
260 component->output[i]->priv->pf_disable = passthrough_port_disable;
261 component->output[i]->priv->pf_flush = passthrough_port_flush;
262 component->output[i]->priv->pf_send = passthrough_port_send;
263 component->output[i]->priv->pf_set_format = passthrough_port_format_commit;
264 component->output[i]->priv->pf_parameter_set = passthrough_port_parameter_set;
265 component->output[i]->buffer_num_min = 1;
266 component->output[i]->buffer_num_recommended = 0;
267 component->output[i]->capabilities = MMAL_PORT_CAPABILITY_PASSTHROUGH;
268 component->output[i]->priv->module->queue = mmal_queue_create();
269 if(!component->output[i]->priv->module->queue)
270 goto error;
271 }
272
273 return MMAL_SUCCESS;
274
275 error:
276 passthrough_component_destroy(component);
277 return status;
278}
279
280MMAL_CONSTRUCTOR(mmal_register_component_passthrough);
281void mmal_register_component_passthrough(void)
282{
283 mmal_component_supplier_register("passthrough", mmal_component_create_passthrough);
284}
285