Initial version of libomxil-vc4 for RPI3
[platform/adaptation/broadcom/libomxil-vc4.git] / interface / mmal / components / passthrough.c
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 "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 /*****************************************************************************/
36 typedef struct MMAL_COMPONENT_MODULE_T
37 {
38    MMAL_BOOL_T error;      /**< Error state */
39
40 } MMAL_COMPONENT_MODULE_T;
41
42 typedef 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 */
51 static 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 */
72 static 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 */
80 static 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 */
97 static 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 */
104 static 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 */
171 static 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
183 static 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  */
216 static 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
280 MMAL_CONSTRUCTOR(mmal_register_component_passthrough);
281 void mmal_register_component_passthrough(void)
282 {
283    mmal_component_supplier_register("passthrough", mmal_component_create_passthrough);
284 }