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 ARTIFICIAL_CAMERA_PORTS_NUM 3
34
35/* Buffering requirements */
36#define OUTPUT_MIN_BUFFER_NUM 1
37#define OUTPUT_RECOMMENDED_BUFFER_NUM 4
38
39#define DEFAULT_WIDTH 320
40#define DEFAULT_HEIGHT 240
41
42/*****************************************************************************/
43typedef struct MMAL_PORT_MODULE_T
44{
45 MMAL_BUFFER_HEADER_VIDEO_SPECIFIC_T frame;
46 unsigned int frame_size;
47 int count;
48
49 MMAL_QUEUE_T *queue;
50
51} MMAL_PORT_MODULE_T;
52
53typedef struct MMAL_COMPONENT_MODULE_T
54{
55 MMAL_STATUS_T status;
56
57} MMAL_COMPONENT_MODULE_T;
58
59/*****************************************************************************/
60static void artificial_camera_do_processing(MMAL_COMPONENT_T *component)
61{
62 MMAL_COMPONENT_MODULE_T *module = component->priv->module;
63 MMAL_BUFFER_HEADER_T *buffer;
64 unsigned int i;
65
66 if (module->status != MMAL_SUCCESS)
67 return;
68
69 /* Loop through all the ports */
70 for (i = 0; i < component->output_num; i++)
71 {
72 MMAL_PORT_T *port = component->output[i];
73
74 buffer = mmal_queue_get(port->priv->module->queue);
75 if (!buffer)
76 continue;
77
78 /* Sanity check the buffer size */
79 if (buffer->alloc_size < port->priv->module->frame_size)
80 {
81 LOG_ERROR("buffer too small (%i/%i)",
82 buffer->alloc_size, port->priv->module->frame_size);
83 module->status = MMAL_EINVAL;
84 mmal_queue_put_back(port->priv->module->queue, buffer);
85 mmal_event_error_send(component, module->status);
86 return;
87 }
88 module->status = mmal_buffer_header_mem_lock(buffer);
89 if (module->status != MMAL_SUCCESS)
90 {
91 LOG_ERROR("invalid buffer (%p, %p)", buffer, buffer->data);
92 mmal_queue_put_back(port->priv->module->queue, buffer);
93 mmal_event_error_send(component, module->status);
94 return;
95 }
96
97 buffer->offset = 0;
98 buffer->length = port->priv->module->frame_size;
99 buffer->type->video = port->priv->module->frame;
100
101 memset(buffer->data, 0xff, buffer->length);
102 if (buffer->type->video.planes > 1)
103 memset(buffer->data + buffer->type->video.offset[1],
104 0x7f - port->priv->module->count++,
105 buffer->length - buffer->type->video.offset[1]);
106
107 mmal_buffer_header_mem_unlock(buffer);
108 mmal_port_buffer_header_callback(port, buffer);
109 }
110
111 vcos_sleep(10); /* Make sure we don't peg all the resources */
112}
113
114/** Destroy a previously created component */
115static MMAL_STATUS_T artificial_camera_component_destroy(MMAL_COMPONENT_T *component)
116{
117 unsigned int i;
118
119 for (i = 0; i < component->output_num; i++)
120 if (component->output[i]->priv->module->queue)
121 mmal_queue_destroy(component->output[i]->priv->module->queue);
122
123 if(component->output_num)
124 mmal_ports_free(component->output, component->output_num);
125
126 vcos_free(component->priv->module);
127 return MMAL_SUCCESS;
128}
129
130/** Enable processing on a port */
131static MMAL_STATUS_T artificial_camera_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
132{
133 MMAL_PARAM_UNUSED(port);
134 MMAL_PARAM_UNUSED(cb);
135 return MMAL_SUCCESS;
136}
137
138/** Flush a port */
139static MMAL_STATUS_T artificial_camera_port_flush(MMAL_PORT_T *port)
140{
141 MMAL_PARAM_UNUSED(port);
142 return MMAL_SUCCESS;
143}
144
145/** Disable processing on a port */
146static MMAL_STATUS_T artificial_camera_port_disable(MMAL_PORT_T *port)
147{
148 MMAL_PARAM_UNUSED(port);
149 return MMAL_SUCCESS;
150}
151
152/** Send a buffer header to a port */
153static MMAL_STATUS_T artificial_camera_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
154{
155 /* Just queue the buffer */
156 mmal_queue_put(port->priv->module->queue, buffer);
157 mmal_component_action_trigger(port->component);
158 return MMAL_SUCCESS;
159}
160
161/** Set format on a port */
162static MMAL_STATUS_T artificial_camera_port_format_commit(MMAL_PORT_T *port)
163{
164 MMAL_PORT_MODULE_T *port_module = port->priv->module;
165 unsigned int width = port->format->es->video.width;
166 unsigned int height = port->format->es->video.height;
167 width = (width + 31) & ~31;
168 height = (height + 15) & ~15;
169
170 /* We only support a few formats */
171 switch(port->format->encoding)
172 {
173 case MMAL_ENCODING_I420:
174 port_module->frame_size = width * height * 3 / 2;
175 port_module->frame.planes = 3;
176 port_module->frame.pitch[0] = width;
177 port_module->frame.offset[1] = port_module->frame.pitch[0] * height;
178 port_module->frame.pitch[1] = width / 2;
179 port_module->frame.offset[2] = port_module->frame.offset[1] + port_module->frame.pitch[1] * height / 2;
180 port_module->frame.pitch[2] = width / 2;
181 break;
182 case MMAL_ENCODING_NV21:
183 port_module->frame_size = width * height * 3 / 2;
184 port_module->frame.planes = 2;
185 port_module->frame.pitch[0] = width;
186 port_module->frame.offset[1] = port_module->frame.pitch[0] * height;
187 port_module->frame.pitch[1] = width;
188 break;
189 case MMAL_ENCODING_I422:
190 port_module->frame_size = width * height * 2;
191 port_module->frame.planes = 3;
192 port_module->frame.pitch[0] = width;
193 port_module->frame.offset[1] = port_module->frame.pitch[0] * height;
194 port_module->frame.pitch[1] = width / 2;
195 port_module->frame.offset[2] = port_module->frame.offset[1] + port_module->frame.pitch[1] * height;
196 port_module->frame.pitch[2] = width / 2;
197 break;
198 default:
199 return MMAL_ENOSYS;
200 }
201
202 port->buffer_size_min = port->buffer_size_recommended = port_module->frame_size;
203 return MMAL_SUCCESS;
204}
205
206/** Set parameter on a port */
207static MMAL_STATUS_T artificial_port_parameter_set(MMAL_PORT_T *port, const MMAL_PARAMETER_HEADER_T *param)
208{
209 MMAL_PARAM_UNUSED(port);
210 switch (param->id)
211 {
212 default:
213 return MMAL_ENOSYS;
214 }
215}
216
217/** Get parameter on a port */
218static MMAL_STATUS_T artificial_port_parameter_get(MMAL_PORT_T *port, MMAL_PARAMETER_HEADER_T *param)
219{
220 MMAL_PARAM_UNUSED(port);
221 switch (param->id)
222 {
223 default:
224 return MMAL_ENOSYS;
225 }
226}
227
228/** Create an instance of a component */
229static MMAL_STATUS_T mmal_component_create_artificial_camera(const char *name, MMAL_COMPONENT_T *component)
230{
231 MMAL_STATUS_T status = MMAL_ENOMEM;
232 unsigned int i;
233 MMAL_PARAM_UNUSED(name);
234
235 /* Allocate our module context */
236 component->priv->module = vcos_calloc(1, sizeof(*component->priv->module), "mmal module");
237 if (!component->priv->module)
238 return MMAL_ENOMEM;
239
240 component->priv->pf_destroy = artificial_camera_component_destroy;
241
242 /* Allocate all the ports for this component */
243 component->output = mmal_ports_alloc(component, ARTIFICIAL_CAMERA_PORTS_NUM, MMAL_PORT_TYPE_OUTPUT,
244 sizeof(MMAL_PORT_MODULE_T));
245 if(!component->output)
246 goto error;
247 component->output_num = ARTIFICIAL_CAMERA_PORTS_NUM;
248
249 for (i = 0; i < component->output_num; i++)
250 {
251 component->output[i]->priv->pf_enable = artificial_camera_port_enable;
252 component->output[i]->priv->pf_disable = artificial_camera_port_disable;
253 component->output[i]->priv->pf_flush = artificial_camera_port_flush;
254 component->output[i]->priv->pf_send = artificial_camera_port_send;
255 component->output[i]->priv->pf_send = artificial_camera_port_send;
256 component->output[i]->priv->pf_set_format = artificial_camera_port_format_commit;
257 component->output[i]->priv->pf_parameter_set = artificial_port_parameter_set;
258 component->output[i]->priv->pf_parameter_get = artificial_port_parameter_get;
259 component->output[i]->format->type = MMAL_ES_TYPE_VIDEO;
260 component->output[i]->format->encoding = MMAL_ENCODING_I420;
261 component->output[i]->format->es->video.width = DEFAULT_WIDTH;
262 component->output[i]->format->es->video.height = DEFAULT_HEIGHT;
263 component->output[i]->buffer_num_min = OUTPUT_MIN_BUFFER_NUM;
264 component->output[i]->buffer_num_recommended = OUTPUT_RECOMMENDED_BUFFER_NUM;
265 artificial_camera_port_format_commit(component->output[i]);
266
267 component->output[i]->priv->module->queue = mmal_queue_create();
268 if (!component->output[i]->priv->module->queue)
269 goto error;
270 }
271
272 status = mmal_component_action_register(component, artificial_camera_do_processing);
273 if (status != MMAL_SUCCESS)
274 goto error;
275
276 return MMAL_SUCCESS;
277
278 error:
279 artificial_camera_component_destroy(component);
280 return status;
281}
282
283MMAL_CONSTRUCTOR(mmal_register_component_artificial_camera);
284void mmal_register_component_artificial_camera(void)
285{
286 mmal_component_supplier_register("artificial_camera", mmal_component_create_artificial_camera);
287}
288