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#include <memory.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <fcntl.h>
32#include <stdarg.h>
33
34#include "mmalcam.h"
35
36#include "interface/mmal/mmal.h"
37#include "interface/mmal/mmal_logging.h"
38#include "interface/mmal/util/mmal_util.h"
39#include "interface/mmal/util/mmal_default_components.h"
40
41#define USE_CONTAINER 0
42
43#if USE_CONTAINER
44#include "containers/containers.h"
45#include "containers/core/containers_utils.h" // FIXME
46#include "containers/containers_codecs.h"
47#endif
48
49/** Number of buffers we want to use for video render. Video render needs at least 2. */
50#define VIDEO_OUTPUT_BUFFERS_NUM 3
51
52/** After this many packets, the container (if any) will be closed and we
53 * start discarding encoded packets.
54 */
55#define MAX_PACKET_COUNT 150
56
57/** Initialise a parameter structure */
58#define INIT_PARAMETER(PARAM, PARAM_ID) \
59 do { \
60 memset(&(PARAM), 0, sizeof(PARAM)); \
61 (PARAM).hdr.id = PARAM_ID; \
62 (PARAM).hdr.size = sizeof(PARAM); \
63 } while (0)
64
65/* Utility functions to manipulate containers */
66#if USE_CONTAINER
67static VC_CONTAINER_T *test_container_open(const char *uri, MMAL_ES_FORMAT_T* format, MMAL_STATUS_T *status);
68static MMAL_STATUS_T test_container_write(VC_CONTAINER_T *container, MMAL_BUFFER_HEADER_T *buffer);
69static VC_CONTAINER_FOURCC_T test_container_encoding_to_codec(uint32_t encoding);
70#endif
71
72/* Utility function to create and setup the camera viewfinder component */
73static MMAL_COMPONENT_T *test_camera_create(MMALCAM_BEHAVIOUR_T *behaviour, MMAL_STATUS_T *status);
74static MMAL_BOOL_T mmalcam_next_effect(MMAL_COMPONENT_T *camera);
75static MMAL_BOOL_T mmalcam_next_rotation(MMAL_COMPONENT_T *camera);
76static MMAL_BOOL_T mmalcam_next_zoom(MMAL_COMPONENT_T *camera);
77static MMAL_BOOL_T mmalcam_next_focus(MMAL_COMPONENT_T *camera);
78static MMAL_BOOL_T mmalcam_reset_focus(MMAL_COMPONENT_T *camera, MMAL_PARAM_FOCUS_T focus_setting);
79static MMAL_BOOL_T mmalcam_next_drc(MMAL_COMPONENT_T *camera);
80static MMAL_BOOL_T mmalcam_next_hdr(MMAL_COMPONENT_T *camera);
81static MMAL_BOOL_T mmalcam_next_colour_param(MMAL_COMPONENT_T *camera, uint32_t id, int min, int max, const char *param_name);
82
83/* Utility function to create and setup the video render component */
84static MMAL_COMPONENT_T *test_video_render_create(MMALCAM_BEHAVIOUR_T *behaviour, MMAL_STATUS_T *status);
85
86/* Utility function to create and setup the video encoder component */
87static MMAL_COMPONENT_T *test_video_encoder_create(MMALCAM_BEHAVIOUR_T *behaviour, MMAL_STATUS_T *status);
88
89/*****************************************************************************/
90
91typedef enum {
92 MMAL_CAM_BUFFER_READY = 1 << 0,
93 MMAL_CAM_AUTOFOCUS_COMPLETE = 1 << 1,
94 MMAL_CAM_ANY_EVENT = 0x7FFFFFFF
95} MMAL_CAM_EVENT_T;
96
97static VCOS_EVENT_FLAGS_T events;
98VCOS_LOG_CAT_T mmalcam_log_category;
99static MMAL_BOOL_T zero_copy;
100static MMAL_BOOL_T tunneling;
101
102static MMAL_BOOL_T enable_zero_copy(void)
103{
104 return zero_copy;
105}
106
107static MMAL_BOOL_T enable_tunneling(void)
108{
109 return tunneling;
110}
111
112/* Buffer header callbacks */
113static void control_bh_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
114{
115 LOG_DEBUG("control_bh_cb %p,%p (cmd=0x%08x)", port, buffer, buffer->cmd);
116 if (buffer->cmd == MMAL_EVENT_PARAMETER_CHANGED)
117 {
118 MMAL_EVENT_PARAMETER_CHANGED_T *param = (MMAL_EVENT_PARAMETER_CHANGED_T *)buffer->data;
119
120 vcos_assert(buffer->length >= sizeof(MMAL_EVENT_PARAMETER_CHANGED_T));
121 vcos_assert(buffer->length == param->hdr.size);
122 switch (param->hdr.id)
123 {
124 case MMAL_PARAMETER_FOCUS_STATUS:
125 vcos_assert(param->hdr.size == sizeof(MMAL_PARAMETER_FOCUS_STATUS_T));
126 {
127 MMAL_PARAMETER_FOCUS_STATUS_T *focus_status = (MMAL_PARAMETER_FOCUS_STATUS_T *)param;
128 LOG_INFO("Focus status: %d", focus_status->status);
129 vcos_event_flags_set(&events, MMAL_CAM_AUTOFOCUS_COMPLETE, VCOS_OR);
130 }
131 break;
132 case MMAL_PARAMETER_CAMERA_NUM:
133 vcos_assert(param->hdr.size == sizeof(MMAL_PARAMETER_UINT32_T));
134 {
135 MMAL_PARAMETER_UINT32_T *camera_num = (MMAL_PARAMETER_UINT32_T *)param;
136 LOG_INFO("Camera number: %d", camera_num->value);
137 }
138 break;
139 default:
140 LOG_ERROR("Unexpected changed event for parameter 0x%08x", param->hdr.id);
141 }
142 }
143 else
144 {
145 LOG_ERROR("Unexpected event, 0x%08x", buffer->cmd);
146 }
147 mmal_buffer_header_release(buffer);
148}
149
150static void generic_output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
151{
152 if (buffer->cmd != 0)
153 {
154 LOG_INFO("%s callback: event %u not supported", port->name, buffer->cmd);
155 mmal_buffer_header_release(buffer);
156 }
157 else
158 {
159 MMAL_QUEUE_T *queue = (MMAL_QUEUE_T *)port->userdata;
160
161 LOG_DEBUG("%s callback", port->name);
162 mmal_queue_put(queue, buffer);
163 }
164
165 vcos_event_flags_set(&events, MMAL_CAM_BUFFER_READY, VCOS_OR);
166}
167
168static void generic_input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
169{
170 if (buffer->cmd != 0)
171 {
172 LOG_INFO("%s callback: event %u not supported", port->name, buffer->cmd);
173 }
174
175 mmal_buffer_header_release(buffer);
176 vcos_event_flags_set(&events, MMAL_CAM_BUFFER_READY, VCOS_OR);
177}
178
179static MMAL_STATUS_T setup_output_port(MMAL_PORT_T *output_port, MMAL_QUEUE_T **p_queue, MMAL_POOL_T **p_pool)
180{
181 MMAL_STATUS_T status = MMAL_ENOMEM;
182 MMAL_QUEUE_T *queue = NULL;
183 MMAL_POOL_T *pool = NULL;
184
185 /* Create a queue for frames filled by the output port.
186 * The main loop will pass these on to the input port. */
187 queue = mmal_queue_create();
188 if (!queue)
189 {
190 LOG_ERROR("failed to create queue for %s", output_port->name);
191 goto error;
192 }
193
194 /* Create pool of buffer headers for the output port to consume */
195 pool = mmal_port_pool_create(output_port, output_port->buffer_num, output_port->buffer_size);
196 if (!pool)
197 {
198 LOG_ERROR("failed to create pool for %s", output_port->name);
199 goto error;
200 }
201
202 output_port->userdata = (void *)queue;
203
204 status = mmal_port_enable(output_port, generic_output_port_cb);
205 if (status != MMAL_SUCCESS)
206 {
207 LOG_ERROR("failed to enable %s", output_port->name);
208 goto error;
209 }
210
211 *p_queue = queue;
212 *p_pool = pool;
213
214 return MMAL_SUCCESS;
215
216error:
217 if (queue)
218 mmal_queue_destroy(queue);
219 if (pool)
220 mmal_pool_destroy(pool);
221
222 return status;
223}
224
225static MMAL_STATUS_T connect_ports(MMAL_PORT_T *output_port, MMAL_PORT_T *input_port, MMAL_QUEUE_T **p_queue, MMAL_POOL_T **p_pool)
226{
227 MMAL_STATUS_T status;
228
229 status = mmal_format_full_copy(input_port->format, output_port->format);
230 if (status != MMAL_SUCCESS)
231 return status;
232
233 status = mmal_port_format_commit(input_port);
234 if (status != MMAL_SUCCESS)
235 return status;
236
237 if (enable_tunneling())
238 {
239 status = mmal_port_connect(output_port, input_port);
240 if (status != MMAL_SUCCESS)
241 return status;
242
243 status = mmal_port_enable(output_port, NULL);
244 if (status != MMAL_SUCCESS)
245 mmal_port_disconnect(output_port);
246
247 return status;
248 }
249
250 /* Non-tunneling setup */
251 input_port->buffer_size = input_port->buffer_size_recommended;
252 if (input_port->buffer_size < input_port->buffer_size_min)
253 input_port->buffer_size = input_port->buffer_size_min;
254 input_port->buffer_num = input_port->buffer_num_recommended;
255 if (input_port->buffer_num < input_port->buffer_num_min)
256 input_port->buffer_num = input_port->buffer_num_min;
257 output_port->buffer_size = output_port->buffer_size_recommended;
258 if (output_port->buffer_size < output_port->buffer_size_min)
259 output_port->buffer_size = output_port->buffer_size_min;
260 output_port->buffer_num = output_port->buffer_num_recommended;
261 if (output_port->buffer_num < output_port->buffer_num_min)
262 output_port->buffer_num = output_port->buffer_num_min;
263
264 input_port->buffer_num = output_port->buffer_num =
265 MMAL_MAX(input_port->buffer_num, output_port->buffer_num);
266 input_port->buffer_size = output_port->buffer_size =
267 MMAL_MAX(input_port->buffer_size, output_port->buffer_size);
268
269 status = setup_output_port(output_port, p_queue, p_pool);
270 if (status != MMAL_SUCCESS)
271 goto error;
272
273 status = mmal_port_enable(input_port, generic_input_port_cb);
274 if (status != MMAL_SUCCESS)
275 goto error;
276
277 return status;
278
279error:
280 if (input_port->is_enabled)
281 mmal_port_disable(input_port);
282 if (output_port->is_enabled)
283 mmal_port_disable(output_port);
284 if (*p_pool)
285 mmal_pool_destroy(*p_pool);
286 if (*p_queue)
287 mmal_queue_destroy(*p_queue);
288
289 return status;
290}
291
292static MMAL_STATUS_T send_buffer_from_queue(MMAL_PORT_T *port, MMAL_QUEUE_T *queue)
293{
294 MMAL_STATUS_T status = MMAL_SUCCESS;
295 MMAL_BUFFER_HEADER_T *buffer;
296
297 if (!queue)
298 return MMAL_SUCCESS;
299
300 buffer = mmal_queue_get(queue);
301
302 if (buffer)
303 {
304 status = mmal_port_send_buffer(port, buffer);
305
306 if (status != MMAL_SUCCESS)
307 {
308 mmal_queue_put_back(queue, buffer);
309 LOG_DEBUG("%s send failed (%i)", port->name, status);
310 }
311 }
312
313 return status;
314}
315
316static MMAL_STATUS_T fill_port_from_pool(MMAL_PORT_T *port, MMAL_POOL_T *pool)
317{
318 MMAL_STATUS_T status = MMAL_SUCCESS;
319 MMAL_QUEUE_T *queue;
320
321 if (!pool)
322 return MMAL_SUCCESS;
323
324 queue = pool->queue;
325 while (status == MMAL_SUCCESS && mmal_queue_length(queue) > 0)
326 status = send_buffer_from_queue(port, queue);
327
328 return status;
329}
330
331static void disable_port(MMAL_PORT_T *port)
332{
333 if (port && port->is_enabled)
334 mmal_port_disable(port);
335}
336
337
338static int parse_vformat(const char* vformat, uint32_t *out_width,
339 uint32_t *out_height, uint32_t *out_encoding)
340{
341 char vcodec[8];
342 uint32_t width, height, encoding;
343
344 // coverity[secure_coding] Scanning integer values, and a string where the length is safe given vcodec declaration
345 if (sscanf(vformat, "%4ux%4u:%7s", &width, &height, vcodec) != 3)
346 {
347 fprintf(stderr, "Error, malformed or unsupported video format: %s\n", vformat);
348 return -1;
349 }
350
351 if (!vcos_strncasecmp(vcodec, "h263", 4))
352 {
353 encoding = MMAL_ENCODING_H263;
354 /* Special case, H263 supports a limited set of resolutions */
355 if (!((width == 128 && height == 96) ||
356 (width == 176 && height == 144) ||
357 (width == 352 && height == 288) ||
358 (width == 704 && height == 576) ||
359 (width == 1408 && height == 1152)))
360 {
361 fprintf(stderr,
362 "Error, only 128x96, 176x144, 352x288, 704x576 and 1408x1152 are supported for H263\n");
363 return -1;
364 }
365 }
366 else if (!vcos_strncasecmp(vcodec, "mp4v", 4))
367 encoding = MMAL_ENCODING_MP4V;
368 else if (!vcos_strncasecmp(vcodec, "h264", 4))
369 encoding = MMAL_ENCODING_H264;
370 else if (!vcos_strncasecmp(vcodec, "jpeg", 4))
371 encoding = MMAL_ENCODING_JPEG;
372 else
373 {
374 fprintf(stderr, "Error, unknown video encoding: %s\n", vcodec);
375 return -1;
376 }
377
378 if (out_width)
379 *out_width = width;
380 if (out_height)
381 *out_height = height;
382 if (out_encoding)
383 *out_encoding = encoding;
384 LOG_DEBUG("Video format: w:%d h:%d codec:%4.4s", width, height, (const char *)&encoding);
385
386 return 0;
387}
388
389/*****************************************************************************/
390int test_mmal_start_camcorder(volatile int *stop, MMALCAM_BEHAVIOUR_T *behaviour)
391{
392 MMAL_STATUS_T status = MMAL_SUCCESS;
393 MMAL_POOL_T *pool_viewfinder = 0, *pool_encoder_in = 0, *pool_encoder_out = 0;
394 MMAL_QUEUE_T *queue_viewfinder = 0, *queue_encoder_in = 0, *queue_encoder_out = 0;
395 MMAL_COMPONENT_T *camera = 0, *encoder = 0, *render = 0;
396 MMAL_PORT_T *viewfinder_port = 0, *video_port = 0, *still_port = 0;
397 MMAL_PORT_T *render_port = 0, *encoder_input = 0, *encoder_output = 0;
398 uint32_t ms_per_change, last_change_ms, set_focus_delay_ms;
399 int packet_count = 0;
400#if USE_CONTAINER
401 VC_CONTAINER_T *container = 0;
402#endif
403 FILE *output = NULL;
404
405 if(vcos_event_flags_create(&events, "MMALCam") != VCOS_SUCCESS)
406 {
407 behaviour->init_result = MMALCAM_INIT_ERROR_EVENT_FLAGS;
408 goto error;
409 }
410
411 zero_copy = behaviour->zero_copy;
412 tunneling = behaviour->tunneling;
413
414 /* Create and setup camera viewfinder component */
415 camera = test_camera_create(behaviour, &status);
416 if(!camera)
417 {
418 behaviour->init_result = MMALCAM_INIT_ERROR_CAMERA;
419 goto error;
420 }
421 viewfinder_port = camera->output[0];
422 video_port = camera->output[1];
423 still_port = camera->output[2];
424
425 /* Create and setup video render component */
426 render = test_video_render_create(behaviour, &status);
427 if(!render)
428 {
429 behaviour->init_result = MMALCAM_INIT_ERROR_RENDER;
430 goto error;
431 }
432 render_port = render->input[0];
433
434 status = connect_ports(viewfinder_port, render_port, &queue_viewfinder, &pool_viewfinder);
435 if (status != MMAL_SUCCESS)
436 {
437 behaviour->init_result = MMALCAM_INIT_ERROR_VIEWFINDER;
438 goto error;
439 }
440
441 if (behaviour->uri)
442 {
443 MMAL_PARAMETER_BOOLEAN_T camera_capture =
444 {{MMAL_PARAMETER_CAPTURE, sizeof(MMAL_PARAMETER_BOOLEAN_T)}, 1};
445
446 /* Create and setup video encoder component */
447 encoder = test_video_encoder_create(behaviour, &status);
448 if(!encoder)
449 {
450 behaviour->init_result = MMALCAM_INIT_ERROR_ENCODER;
451 goto error;
452 }
453 encoder_input = encoder->input[0];
454 encoder_output = encoder->output[0];
455
456 if (encoder_output->format->encoding == MMAL_ENCODING_JPEG)
457 video_port = still_port;
458
459 status = connect_ports(video_port, encoder_input, &queue_encoder_in, &pool_encoder_in);
460 if (status != MMAL_SUCCESS)
461 {
462 behaviour->init_result = MMALCAM_INIT_ERROR_ENCODER_IN;
463 goto error;
464 }
465
466 status = setup_output_port(encoder_output, &queue_encoder_out, &pool_encoder_out);
467 if (status != MMAL_SUCCESS)
468 {
469 behaviour->init_result = MMALCAM_INIT_ERROR_ENCODER_OUT;
470 goto error;
471 }
472
473 status = mmal_port_parameter_set(video_port, &camera_capture.hdr);
474 if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
475 {
476 behaviour->init_result = MMALCAM_INIT_ERROR_CAMERA_CAPTURE;
477 goto error;
478 }
479
480#if USE_CONTAINER
481 container = test_container_open(behaviour->uri, encoder_output->format, &status);
482 if (!container)
483 {
484 /* Notify user, carry on discarding encoded output buffers */
485 fprintf(stderr, "Error (%i) opening container: %s\n", status, behaviour->uri);
486 }
487#else
488
489 output = fopen(behaviour->uri, "wb");
490 if(!output)
491 {
492 /* Notify user, carry on discarding encoded output buffers */
493 fprintf(stderr, "Error opening output file: %s\n", behaviour->uri);
494 }
495#endif
496 }
497
498 /* Initialisation now complete */
499 behaviour->init_result = MMALCAM_INIT_SUCCESS;
500 vcos_semaphore_post(&behaviour->init_sem);
501
502 ms_per_change = behaviour->seconds_per_change * 1000;
503 last_change_ms = vcos_get_ms();
504 set_focus_delay_ms = 1000;
505
506 while(1)
507 {
508 MMAL_BUFFER_HEADER_T *buffer;
509 VCOS_UNSIGNED set;
510
511 vcos_event_flags_get(&events, MMAL_CAM_ANY_EVENT, VCOS_OR_CONSUME, VCOS_TICKS_TO_MS(2), &set);
512 if(*stop) break;
513
514 if (behaviour->focus_test != MMAL_PARAM_FOCUS_MAX)
515 {
516 if (set & MMAL_CAM_AUTOFOCUS_COMPLETE ||
517 (set_focus_delay_ms && (vcos_get_ms() - last_change_ms) >= set_focus_delay_ms))
518 {
519 set_focus_delay_ms = 0;
520 mmalcam_reset_focus(camera, behaviour->focus_test);
521 }
522 }
523
524 /* Send empty buffers to the output ports */
525 status = fill_port_from_pool(viewfinder_port, pool_viewfinder);
526 if (status != MMAL_SUCCESS)
527 break;
528 status = fill_port_from_pool(video_port, pool_encoder_in);
529 if (status != MMAL_SUCCESS)
530 break;
531 status = fill_port_from_pool(encoder_output, pool_encoder_out);
532 if (status != MMAL_SUCCESS)
533 break;
534
535 /* Process filled output buffers */
536 status = send_buffer_from_queue(render_port, queue_viewfinder);
537 if (status != MMAL_SUCCESS)
538 break;
539 status = send_buffer_from_queue(encoder_input, queue_encoder_in);
540 if (status != MMAL_SUCCESS)
541 break;
542
543 /* Process output buffers from encoder */
544 if (queue_encoder_out)
545 {
546 buffer = mmal_queue_get(queue_encoder_out);
547 if (buffer)
548 {
549 if (output
550#if USE_CONTAINER
551 || container
552#endif
553 )
554 {
555 mmal_buffer_header_mem_lock(buffer);
556#if USE_CONTAINER
557 test_container_write(container, buffer);
558#else
559 LOG_ERROR("Write %d bytes of data from %p", buffer->length, buffer->data);
560 fwrite(buffer->data, 1, buffer->length, output);
561#endif
562 mmal_buffer_header_mem_unlock(buffer);
563 packet_count++;
564 if (packet_count > MAX_PACKET_COUNT)
565 {
566#if USE_CONTAINER
567 vc_container_close(container);
568 container = 0;
569#else
570 fclose(output);
571#endif
572 output = NULL;
573 fprintf(stderr, "All packets written\n");
574 }
575 }
576 mmal_buffer_header_release(buffer);
577 }
578 }
579
580 /* Change a camera parameter if requested */
581 if (ms_per_change != 0)
582 {
583 if((vcos_get_ms() - last_change_ms) >= ms_per_change)
584 {
585 last_change_ms = vcos_get_ms();
586 switch (behaviour->change)
587 {
588 case MMALCAM_CHANGE_IMAGE_EFFECT:
589 if (!mmalcam_next_effect(camera))
590 *stop = 1;
591 break;
592 case MMALCAM_CHANGE_ROTATION:
593 if (!mmalcam_next_rotation(camera))
594 *stop = 1;
595 break;
596 case MMALCAM_CHANGE_ZOOM:
597 if (!mmalcam_next_zoom(camera))
598 *stop = 1;
599 break;
600 case MMALCAM_CHANGE_FOCUS:
601 if (!mmalcam_next_focus(camera))
602 *stop = 1;
603 break;
604 case MMALCAM_CHANGE_DRC:
605 if (!mmalcam_next_drc(camera))
606 *stop = 1;
607 break;
608 case MMALCAM_CHANGE_HDR:
609 if (!mmalcam_next_hdr(camera))
610 *stop = 1;
611 break;
612 case MMALCAM_CHANGE_CONTRAST:
613 if (!mmalcam_next_colour_param(camera, MMAL_PARAMETER_CONTRAST, -100, 100, "contrast"))
614 *stop = 1;
615 break;
616 case MMALCAM_CHANGE_BRIGHTNESS:
617 if (!mmalcam_next_colour_param(camera, MMAL_PARAMETER_BRIGHTNESS, 0, 100, "brightness"))
618 *stop = 1;
619 break;
620 case MMALCAM_CHANGE_SATURATION:
621 if (!mmalcam_next_colour_param(camera, MMAL_PARAMETER_SATURATION, -100, 100, "saturation"))
622 *stop = 1;
623 break;
624 case MMALCAM_CHANGE_SHARPNESS:
625 if (!mmalcam_next_colour_param(camera, MMAL_PARAMETER_SHARPNESS, -100, 100, "sharpness"))
626 *stop = 1;
627 break;
628 default:
629 LOG_ERROR("Unexpected change behaviour: %d", behaviour->change);
630 break;
631 }
632 }
633 }
634 }
635
636 /* Disable ports */
637 disable_port(viewfinder_port);
638 disable_port(render_port);
639 disable_port(video_port);
640 disable_port(encoder_input);
641 disable_port(encoder_output);
642
643 /* Disable components */
644 mmal_component_disable(render);
645 if (encoder)
646 mmal_component_disable(encoder);
647 mmal_component_disable(camera);
648
649 INIT_PARAMETER(behaviour->render_stats, MMAL_PARAMETER_STATISTICS);
650 mmal_port_parameter_get(render_port, &behaviour->render_stats.hdr);
651 if (encoder)
652 {
653 INIT_PARAMETER(behaviour->encoder_stats, MMAL_PARAMETER_STATISTICS);
654 mmal_port_parameter_get(encoder_output, &behaviour->encoder_stats.hdr);
655 }
656
657 error:
658 /* The pools need to be destroyed first since they are owned by the components */
659 if(pool_viewfinder)
660 mmal_port_pool_destroy(viewfinder_port, pool_viewfinder);
661 if(pool_encoder_in)
662 mmal_port_pool_destroy(video_port, pool_encoder_in);
663 if(pool_encoder_out)
664 mmal_port_pool_destroy(encoder_output, pool_encoder_out);
665
666 if(render)
667 mmal_component_destroy(render);
668 if(encoder)
669 mmal_component_destroy(encoder);
670 if(camera)
671 mmal_component_destroy(camera);
672
673 if(queue_viewfinder)
674 mmal_queue_destroy(queue_viewfinder);
675 if(queue_encoder_in)
676 mmal_queue_destroy(queue_encoder_in);
677 if(queue_encoder_out)
678 mmal_queue_destroy(queue_encoder_out);
679
680#if USE_CONTAINER
681 if(container)
682 vc_container_close(container);
683#endif
684 if(output)
685 fclose(output);
686
687 vcos_event_flags_delete(&events);
688
689 if (packet_count)
690 printf("Packet count: %d\n", packet_count);
691
692 if (behaviour->init_result != MMALCAM_INIT_SUCCESS)
693 vcos_semaphore_post(&behaviour->init_sem);
694
695 return (int)status;
696}
697
698/*****************************************************************************/
699static MMAL_COMPONENT_T *test_camera_create(MMALCAM_BEHAVIOUR_T *behaviour, MMAL_STATUS_T *status)
700{
701 MMAL_COMPONENT_T *camera = 0;
702 MMAL_ES_FORMAT_T *format;
703 MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T change_event_request =
704 {{MMAL_PARAMETER_CHANGE_EVENT_REQUEST, sizeof(MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T)}, 0, 1};
705 MMAL_PORT_T *viewfinder_port = NULL, *video_port = NULL, *still_port = NULL;
706 uint32_t width, height;
707 MMAL_PARAMETER_INT32_T camera_num =
708 {{MMAL_PARAMETER_CAMERA_NUM, sizeof(camera_num)},0};
709
710 /* Create the component */
711 *status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera);
712 if(*status != MMAL_SUCCESS)
713 {
714 LOG_ERROR("couldn't create camera");
715 goto error;
716 }
717 if(!camera->output_num)
718 {
719 LOG_ERROR("camera doesn't have output ports");
720 *status = MMAL_EINVAL;
721 goto error;
722 }
723
724 viewfinder_port = camera->output[0];
725 video_port = camera->output[1];
726 still_port = camera->output[2];
727
728 change_event_request.change_id = MMAL_PARAMETER_FOCUS_STATUS;
729 *status = mmal_port_parameter_set(camera->control, &change_event_request.hdr);
730 if (*status != MMAL_SUCCESS && *status != MMAL_ENOSYS)
731 {
732 LOG_ERROR("No focus status change events");
733 }
734 camera_num.value = behaviour->camera_num;
735 *status = mmal_port_parameter_set(camera->control, &camera_num.hdr);
736 if (*status != MMAL_SUCCESS && *status != MMAL_ENOSYS)
737 {
738 LOG_ERROR("No camera number change events");
739 }
740 if (enable_zero_copy())
741 {
742 MMAL_PARAMETER_BOOLEAN_T param_zc =
743 {{MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T)}, 1};
744 *status = mmal_port_parameter_set(viewfinder_port, &param_zc.hdr);
745 if( *status != MMAL_SUCCESS && *status != MMAL_ENOSYS )
746 {
747 LOG_ERROR("failed to set zero copy on camera output");
748 goto error;
749 }
750 LOG_INFO("enabled zero copy on camera");
751 *status = mmal_port_parameter_set(video_port, &param_zc.hdr);
752 if( *status != MMAL_SUCCESS && *status != MMAL_ENOSYS )
753 {
754 LOG_ERROR("failed to set zero copy on camera output");
755 goto error;
756 }
757 *status = mmal_port_parameter_set(still_port, &param_zc.hdr);
758 if( *status != MMAL_SUCCESS && *status != MMAL_ENOSYS )
759 {
760 LOG_ERROR("failed to set zero copy on camera output");
761 goto error;
762 }
763 }
764
765 if ( behaviour->change == MMALCAM_CHANGE_HDR )
766 {
767 MMAL_PARAMETER_ALGORITHM_CONTROL_T algo_ctrl = {{MMAL_PARAMETER_ALGORITHM_CONTROL, sizeof(MMAL_PARAMETER_ALGORITHM_CONTROL_T)},
768 MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_HIGH_DYNAMIC_RANGE, 1 };
769 mmal_port_parameter_set(camera->control, &algo_ctrl.hdr);
770 }
771
772 *status = mmal_port_enable(camera->control, control_bh_cb);
773 if (*status)
774 {
775 LOG_ERROR("control port couldn't be enabled: %d", *status);
776 goto error;
777 }
778
779 /* Set camera viewfinder port format */
780 if (parse_vformat(behaviour->vformat, &width, &height, NULL))
781 {
782 *status = MMAL_EINVAL;
783 goto error;
784 }
785
786 /* Default to integer frame rate in numerator */
787 if (!behaviour->frame_rate.den)
788 behaviour->frame_rate.den = 1;
789
790 {
791 MMAL_PARAMETER_CAMERA_CONFIG_T cam_config = {{MMAL_PARAMETER_CAMERA_CONFIG,sizeof(cam_config)},
792 .max_stills_w = width,
793 .max_stills_h = height,
794 .stills_yuv422 = 0,
795 .one_shot_stills = 0,
796 .max_preview_video_w = width,
797 .max_preview_video_h = height,
798 .num_preview_video_frames = 3,
799 .stills_capture_circular_buffer_height = 0,
800 .fast_preview_resume = 0,
801 /* No way of using fast resume in Android, as preview
802 * automatically stops on capture.
803 */
804 .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RESET_STC
805 };
806
807 mmal_port_parameter_set(camera->control, &cam_config.hdr);
808 }
809
810 /* Set up the viewfinder port format */
811 format = viewfinder_port->format;
812 if (behaviour->opaque)
813 format->encoding = MMAL_ENCODING_OPAQUE;
814 else
815 format->encoding = MMAL_ENCODING_I420;
816
817 format->es->video.width = width;
818 format->es->video.height = height;
819 format->es->video.crop.x = 0;
820 format->es->video.crop.y = 0;
821 format->es->video.crop.width = width;
822 format->es->video.crop.height = height;
823 format->es->video.frame_rate = behaviour->frame_rate;
824
825 *status = mmal_port_format_commit(viewfinder_port);
826 if(*status)
827 {
828 LOG_ERROR("camera viewfinder format couldn't be set");
829 goto error;
830 }
831
832 /* Set the same format on the video (for encoder) port */
833 mmal_format_full_copy(video_port->format, format);
834 *status = mmal_port_format_commit(video_port);
835 if(*status)
836 {
837 LOG_ERROR("camera video format couldn't be set");
838 goto error;
839 }
840
841 /* Ensure there are enough buffers to avoid dropping frames */
842 if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
843 video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
844
845 /* Set the same format on the still (for encoder) port */
846 mmal_format_full_copy(still_port->format, format);
847 *status = mmal_port_format_commit(still_port);
848 if(*status)
849 {
850 LOG_ERROR("camera still format couldn't be set");
851 goto error;
852 }
853
854 /* Ensure there are enough buffers to avoid dropping frames */
855 if (still_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
856 still_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
857
858 /* Enable component */
859 *status = mmal_component_enable(camera);
860 if(*status)
861 {
862 LOG_ERROR("camera component couldn't be enabled");
863 goto error;
864 }
865
866 return camera;
867
868 error:
869 if(camera) mmal_component_destroy(camera);
870 return 0;
871}
872
873/*****************************************************************************/
874static MMAL_BOOL_T mmalcam_next_effect(MMAL_COMPONENT_T *camera)
875{
876 static const MMAL_PARAM_IMAGEFX_T effects[] = {
877 MMAL_PARAM_IMAGEFX_NONE,
878 MMAL_PARAM_IMAGEFX_NEGATIVE,
879 MMAL_PARAM_IMAGEFX_SOLARIZE
880 };
881 static unsigned int index;
882 MMAL_PARAMETER_IMAGEFX_T image_fx = {{ MMAL_PARAMETER_IMAGE_EFFECT, sizeof(image_fx)},0};
883 MMAL_PARAMETER_IMAGEFX_T image_fx_check = {{ MMAL_PARAMETER_IMAGE_EFFECT, sizeof(image_fx)},0};
884 MMAL_STATUS_T result;
885
886 index++;
887 if(index >= countof(effects))
888 index = 0;
889 image_fx.value = effects[index];
890 result = mmal_port_parameter_set(camera->control, &image_fx.hdr);
891 if (result != MMAL_SUCCESS)
892 {
893 LOG_ERROR("Failed to set image effect, %d", result);
894 return MMAL_FALSE;
895 }
896 result = mmal_port_parameter_get(camera->control, &image_fx_check.hdr);
897 if (result != MMAL_SUCCESS)
898 {
899 LOG_ERROR("Failed to retrieve image effect, %d", result);
900 return MMAL_FALSE;
901 }
902 if (memcmp(&image_fx, &image_fx_check, sizeof(image_fx)) != 0)
903 {
904 LOG_ERROR("Image effect set (%d) was not retrieved (%d)", image_fx.value, image_fx_check.value);
905 return MMAL_FALSE;
906 }
907 return MMAL_TRUE;
908}
909
910/*****************************************************************************/
911static MMAL_BOOL_T mmalcam_next_rotation(MMAL_COMPONENT_T *camera)
912{
913 static MMAL_PARAMETER_UINT32_T rotate = {{MMAL_PARAMETER_ROTATION,sizeof(rotate)},0};
914 MMAL_PARAMETER_UINT32_T rotate_check = {{MMAL_PARAMETER_ROTATION,sizeof(rotate_check)},0};
915 MMAL_STATUS_T result;
916
917 rotate.value += 90;
918 if(rotate.value == 360)
919 rotate.value = 0;
920 result = mmal_port_parameter_set(camera->output[0], &rotate.hdr);
921 if (result != MMAL_SUCCESS)
922 {
923 LOG_ERROR("Failed to set rotation, %d", result);
924 return MMAL_FALSE;
925 }
926 result = mmal_port_parameter_get(camera->output[0], &rotate_check.hdr);
927 if (result != MMAL_SUCCESS)
928 {
929 LOG_ERROR("Failed to retrieve rotation, %d", result);
930 return MMAL_FALSE;
931 }
932 if (memcmp(&rotate, &rotate_check, sizeof(rotate)) != 0)
933 {
934 LOG_ERROR("Rotation set (%d) was not retrieved (%d)", rotate.value, rotate_check.value);
935 return MMAL_FALSE;
936 }
937 return MMAL_TRUE;
938}
939
940/*****************************************************************************/
941static MMAL_BOOL_T mmalcam_next_zoom(MMAL_COMPONENT_T *camera)
942{
943 static MMAL_PARAMETER_SCALEFACTOR_T scale = {{MMAL_PARAMETER_ZOOM,sizeof(scale)},1<<16,1<<16};
944 static int32_t dirn = 1 << 14;
945 MMAL_PARAMETER_SCALEFACTOR_T scale_check = {{MMAL_PARAMETER_ZOOM,sizeof(scale_check)},0,0};
946 MMAL_STATUS_T result;
947
948 scale.scale_x += dirn;
949 scale.scale_y += dirn;
950 if (scale.scale_x >= 4<<16 || scale.scale_x <= 1<<16)
951 dirn = -dirn;
952 result = mmal_port_parameter_set(camera->control, &scale.hdr);
953 if (result != MMAL_SUCCESS)
954 {
955 LOG_ERROR("Failed to set scale, %d", result);
956 return MMAL_FALSE;
957 }
958 result = mmal_port_parameter_get(camera->control, &scale_check.hdr);
959 if (result != MMAL_SUCCESS)
960 {
961 LOG_ERROR("Failed to retrieve scale, %d", result);
962 return MMAL_FALSE;
963 }
964 if (memcmp(&scale, &scale_check, sizeof(scale)) != 0)
965 {
966 LOG_ERROR("Scale set (%d,%d) was not retrieved (%d,%d)",
967 scale.scale_x, scale.scale_y, scale_check.scale_x, scale_check.scale_y);
968 return MMAL_FALSE;
969 }
970 return MMAL_TRUE;
971}
972
973/*****************************************************************************/
974static MMAL_BOOL_T mmalcam_next_focus(MMAL_COMPONENT_T *camera)
975{
976 static const MMAL_PARAM_FOCUS_T focus_setting[] = {
977 MMAL_PARAM_FOCUS_AUTO,
978 MMAL_PARAM_FOCUS_AUTO_MACRO,
979 MMAL_PARAM_FOCUS_CAF,
980 MMAL_PARAM_FOCUS_FIXED_INFINITY,
981 MMAL_PARAM_FOCUS_FIXED_HYPERFOCAL,
982 MMAL_PARAM_FOCUS_FIXED_MACRO,
983 MMAL_PARAM_FOCUS_EDOF,
984 };
985 static unsigned int index;
986 static MMAL_PARAMETER_FOCUS_T focus = {{MMAL_PARAMETER_FOCUS,sizeof(focus)},0};
987 static MMAL_PARAMETER_FOCUS_T focus_check = {{MMAL_PARAMETER_FOCUS,sizeof(focus)},0};
988 MMAL_STATUS_T result;
989
990 index++;
991 if(index >= countof(focus_setting))
992 index = MMAL_FALSE;
993 focus.value = focus_setting[index];
994 result = mmal_port_parameter_set(camera->control, &focus.hdr);
995 if (result != MMAL_SUCCESS)
996 {
997 LOG_ERROR("Failed to set focus to %d", focus.value);
998 /* As this depends on the camera module, do not fail */
999 return MMAL_TRUE;
1000 }
1001 result = mmal_port_parameter_get(camera->control, &focus_check.hdr);
1002 if (result != MMAL_SUCCESS)
1003 {
1004 LOG_ERROR("Failed to retrieve focus, %d", result);
1005 return MMAL_FALSE;
1006 }
1007 /* Focus setting is asynchronous, so the value read back may not match what was set */
1008 return MMAL_TRUE;
1009}
1010
1011/*****************************************************************************/
1012static MMAL_BOOL_T mmalcam_reset_focus(MMAL_COMPONENT_T *camera, MMAL_PARAM_FOCUS_T focus_setting)
1013{
1014 MMAL_PARAMETER_FOCUS_T focus = {{MMAL_PARAMETER_FOCUS, sizeof(focus)},MMAL_PARAM_FOCUS_FIXED_HYPERFOCAL};
1015 MMAL_STATUS_T result;
1016
1017 result = mmal_port_parameter_set(camera->control, &focus.hdr);
1018 if (result != MMAL_SUCCESS)
1019 {
1020 LOG_ERROR("Failed to set focus to HYPERFOCAL, result %d", result);
1021 return MMAL_FALSE;
1022 }
1023 focus.value = focus_setting;
1024 result = mmal_port_parameter_set(camera->control, &focus.hdr);
1025 if (result != MMAL_SUCCESS)
1026 {
1027 LOG_ERROR("Failed to set focus to %d, result %d", focus_setting, result);
1028 return MMAL_FALSE;
1029 }
1030 return MMAL_TRUE;
1031}
1032
1033/*****************************************************************************/
1034static MMAL_BOOL_T mmalcam_next_drc(MMAL_COMPONENT_T *camera)
1035{
1036 static const MMAL_PARAMETER_DRC_STRENGTH_T drc_setting[] = {
1037 MMAL_PARAMETER_DRC_STRENGTH_OFF,
1038 MMAL_PARAMETER_DRC_STRENGTH_LOW,
1039 MMAL_PARAMETER_DRC_STRENGTH_MEDIUM,
1040 MMAL_PARAMETER_DRC_STRENGTH_HIGH
1041 };
1042 static unsigned int index;
1043 MMAL_STATUS_T result;
1044 MMAL_PARAMETER_DRC_T drc = {{MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION,sizeof(drc)},0};
1045 MMAL_PARAMETER_DRC_T drc_check = {{MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION,sizeof(drc_check)},0};
1046
1047 index++;
1048 if(index >= countof(drc_setting))
1049 index = 0;
1050 drc.strength = drc_setting[index];
1051
1052 result = mmal_port_parameter_set(camera->control, &drc.hdr);
1053 if (result != MMAL_SUCCESS)
1054 {
1055 LOG_ERROR("Failed to set drc, %d", result);
1056 return MMAL_FALSE;
1057 }
1058 result = mmal_port_parameter_get(camera->control, &drc_check.hdr);
1059 if (result != MMAL_SUCCESS)
1060 {
1061 LOG_ERROR("Failed to retrieve drc, %d", result);
1062 return MMAL_FALSE;
1063 }
1064 if (memcmp(&drc, &drc_check, sizeof(drc)) != 0)
1065 {
1066 LOG_ERROR("DRC set (%d) was not retrieved (%d)", drc.strength, drc_check.strength);
1067 return MMAL_FALSE;
1068 }
1069 return MMAL_TRUE;
1070}
1071
1072/*****************************************************************************/
1073static MMAL_BOOL_T mmalcam_next_hdr(MMAL_COMPONENT_T *camera)
1074{
1075 static const MMAL_BOOL_T hdr_setting[] = {
1076 MMAL_FALSE,
1077 MMAL_TRUE,
1078 };
1079 static unsigned int index;
1080 MMAL_STATUS_T result;
1081 MMAL_PARAMETER_BOOLEAN_T hdr = {{MMAL_PARAMETER_HIGH_DYNAMIC_RANGE,sizeof(hdr)},0};
1082 MMAL_PARAMETER_BOOLEAN_T hdr_check = {{MMAL_PARAMETER_HIGH_DYNAMIC_RANGE,sizeof(hdr_check)},0};
1083
1084 index++;
1085 if(index >= countof(hdr_setting))
1086 index = 0;
1087 hdr.enable = hdr_setting[index];
1088
1089 result = mmal_port_parameter_set(camera->control, &hdr.hdr);
1090 if (result != MMAL_SUCCESS)
1091 {
1092 LOG_ERROR("Failed to set hdr, %d", result);
1093 return MMAL_FALSE;
1094 }
1095 result = mmal_port_parameter_get(camera->control, &hdr_check.hdr);
1096 if (result != MMAL_SUCCESS)
1097 {
1098 LOG_ERROR("Failed to retrieve hdr, %d", result);
1099 return MMAL_FALSE;
1100 }
1101 if (memcmp(&hdr, &hdr_check, sizeof(hdr)) != 0)
1102 {
1103 LOG_ERROR("HDR set (%d) was not retrieved (%d)", hdr.enable, hdr_check.enable);
1104 return MMAL_FALSE;
1105 }
1106 return MMAL_TRUE;
1107}
1108
1109/*****************************************************************************/
1110/* Contrast, brightness, saturation, and sharpness all take the same format,
1111 * but need different parameter IDs, and brightness is 0-100, not -100 to 100.
1112 */
1113static MMAL_BOOL_T mmalcam_next_colour_param(MMAL_COMPONENT_T *camera, uint32_t id, int min, int max, const char *param_name)
1114{
1115 static MMAL_PARAMETER_RATIONAL_T param = {{MMAL_PARAMETER_GROUP_CAMERA,sizeof(param)},{0,100}};
1116 MMAL_PARAMETER_RATIONAL_T param_check = {{MMAL_PARAMETER_GROUP_CAMERA,sizeof(param_check)},{0,100}};
1117 MMAL_STATUS_T result;
1118 param.hdr.id = id;
1119 param_check.hdr.id = id;
1120
1121 param.value.num += 20;
1122 if(param.value.num < min || param.value.num > max)
1123 param.value.num = min;
1124 result = mmal_port_parameter_set(camera->control, &param.hdr);
1125 if (result != MMAL_SUCCESS)
1126 {
1127 LOG_ERROR("Failed to set %s, %d", param_name, result);
1128 return MMAL_FALSE;
1129 }
1130 result = mmal_port_parameter_get(camera->control, &param_check.hdr);
1131 if (result != MMAL_SUCCESS)
1132 {
1133 LOG_ERROR("Failed to retrieve %s, %d", param_name, result);
1134 return MMAL_FALSE;
1135 }
1136 if (memcmp(&param, &param_check, sizeof(param)) != 0)
1137 {
1138 LOG_ERROR("%s set (%d/%d) was not retrieved (%d/%d)", param_name,
1139 param.value.num, param.value.den,
1140 param_check.value.num, param_check.value.den);
1141 return MMAL_FALSE;
1142 }
1143 return MMAL_TRUE;
1144}
1145
1146
1147/*****************************************************************************/
1148static MMAL_COMPONENT_T *test_video_render_create(MMALCAM_BEHAVIOUR_T *behaviour, MMAL_STATUS_T *status)
1149{
1150 MMAL_COMPONENT_T *render = 0;
1151 MMAL_PORT_T *render_port = NULL;
1152
1153 *status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &render);
1154 if(*status != MMAL_SUCCESS)
1155 {
1156 LOG_ERROR("couldn't create video render");
1157 goto error;
1158 }
1159 if(!render->input_num)
1160 {
1161 LOG_ERROR("video render doesn't have input ports");
1162 *status = MMAL_EINVAL;
1163 goto error;
1164 }
1165
1166 render_port = render->input[0];
1167
1168 /* Give higher priority to the overlay layer */
1169 MMAL_DISPLAYREGION_T param;
1170 param.hdr.id = MMAL_PARAMETER_DISPLAYREGION;
1171 param.hdr.size = sizeof(MMAL_DISPLAYREGION_T);
1172 param.set = MMAL_DISPLAY_SET_LAYER;
1173 param.layer = behaviour->layer;
1174 if (behaviour->display_area.width && behaviour->display_area.height)
1175 {
1176 param.set |= MMAL_DISPLAY_SET_DEST_RECT | MMAL_DISPLAY_SET_FULLSCREEN;
1177 param.fullscreen = 0;
1178 param.dest_rect = behaviour->display_area;
1179 }
1180 *status = mmal_port_parameter_set( render_port, &param.hdr );
1181 if (*status != MMAL_SUCCESS && *status != MMAL_ENOSYS)
1182 {
1183 LOG_ERROR("could not set video render display properties (%u)", *status);
1184 goto error;
1185 }
1186
1187 if (enable_zero_copy())
1188 {
1189 MMAL_PARAMETER_BOOLEAN_T param_zc =
1190 {{MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T)}, 1};
1191 *status = mmal_port_parameter_set(render_port, &param_zc.hdr);
1192 if (*status != MMAL_SUCCESS && *status != MMAL_ENOSYS)
1193 {
1194 LOG_ERROR("failed to set zero copy on render input");
1195 goto error;
1196 }
1197 LOG_INFO("enabled zero copy on render");
1198 }
1199
1200 if (behaviour->opaque)
1201 {
1202 render_port->format->encoding = MMAL_ENCODING_OPAQUE;
1203 }
1204
1205 /* Enable component */
1206 *status = mmal_component_enable(render);
1207 if(*status)
1208 {
1209 LOG_ERROR("video render component couldn't be enabled (%u)", *status);
1210 goto error;
1211 }
1212
1213 return render;
1214
1215 error:
1216 if(render) mmal_component_destroy(render);
1217 return 0;
1218}
1219
1220/*****************************************************************************/
1221static MMAL_COMPONENT_T *test_video_encoder_create(MMALCAM_BEHAVIOUR_T *behaviour, MMAL_STATUS_T *status)
1222{
1223 MMAL_COMPONENT_T *encoder = 0;
1224 MMAL_PORT_T *encoder_input = NULL, *encoder_output = NULL;
1225 const char *component_name = MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER;
1226 uint32_t encoding;
1227
1228 /* Set the port format */
1229 if (parse_vformat(behaviour->vformat, 0, 0, &encoding))
1230 {
1231 *status = MMAL_EINVAL;
1232 goto error;
1233 }
1234
1235 if (encoding == MMAL_ENCODING_JPEG)
1236 component_name = MMAL_COMPONENT_DEFAULT_IMAGE_ENCODER;
1237
1238 *status = mmal_component_create(component_name, &encoder);
1239 if(*status != MMAL_SUCCESS)
1240 {
1241 LOG_ERROR("couldn't create video encoder");
1242 goto error;
1243 }
1244 if(!encoder->input_num || !encoder->output_num)
1245 {
1246 LOG_ERROR("video encoder doesn't have input/output ports");
1247 *status = MMAL_EINVAL;
1248 goto error;
1249 }
1250
1251 encoder_input = encoder->input[0];
1252 encoder_output = encoder->output[0];
1253
1254 mmal_format_copy(encoder_output->format, encoder_input->format);
1255 encoder_output->format->encoding = encoding;
1256 encoder_output->format->bitrate = behaviour->bit_rate;
1257 *status = mmal_port_format_commit(encoder_output);
1258 if(*status != MMAL_SUCCESS)
1259 {
1260 LOG_ERROR("format not set on video encoder output port");
1261 goto error;
1262 }
1263 encoder_output->buffer_size = encoder_output->buffer_size_recommended;
1264 if (encoder_output->buffer_size < encoder_output->buffer_size_min)
1265 encoder_output->buffer_size = encoder_output->buffer_size_min;
1266 encoder_output->buffer_num = encoder_output->buffer_num_recommended;
1267 if (encoder_output->buffer_num < encoder_output->buffer_num_min)
1268 encoder_output->buffer_num = encoder_output->buffer_num_min;
1269
1270 if (enable_zero_copy())
1271 {
1272 MMAL_PARAMETER_BOOLEAN_T param_zc =
1273 {{MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T)}, 1};
1274 *status = mmal_port_parameter_set(encoder_output, &param_zc.hdr);
1275 if (*status != MMAL_SUCCESS && *status != MMAL_ENOSYS)
1276 {
1277 LOG_ERROR("failed to set zero copy on encoder output");
1278 goto error;
1279 }
1280 *status = mmal_port_parameter_set(encoder_input, &param_zc.hdr);
1281 if (*status != MMAL_SUCCESS && *status != MMAL_ENOSYS)
1282 {
1283 LOG_ERROR("failed to set zero copy on encoder input");
1284 goto error;
1285 }
1286 LOG_INFO("enabled zero copy on encoder");
1287 }
1288
1289 if (behaviour->opaque)
1290 {
1291 encoder_input->format->encoding = MMAL_ENCODING_OPAQUE;
1292 }
1293
1294 /* Enable component */
1295 *status = mmal_component_enable(encoder);
1296 if(*status)
1297 {
1298 LOG_ERROR("video encoder component couldn't be enabled");
1299 goto error;
1300 }
1301
1302 return encoder;
1303
1304 error:
1305 if(encoder) mmal_component_destroy(encoder);
1306 return 0;
1307}
1308
1309#if USE_CONTAINER
1310/*****************************************************************************/
1311static MMAL_STATUS_T test_container_to_mmal_status(VC_CONTAINER_STATUS_T status)
1312{
1313 switch (status)
1314 {
1315 case VC_CONTAINER_SUCCESS:
1316 case VC_CONTAINER_ERROR_NOT_READY:
1317 return MMAL_SUCCESS;
1318 case VC_CONTAINER_ERROR_LIMIT_REACHED:
1319 case VC_CONTAINER_ERROR_OUT_OF_SPACE:
1320 return MMAL_ENOSPC;
1321 case VC_CONTAINER_ERROR_URI_NOT_FOUND:
1322 return MMAL_ENOENT;
1323 default:
1324 return MMAL_ENXIO;
1325 }
1326}
1327
1328/*****************************************************************************/
1329static VC_CONTAINER_T *test_container_open(const char *uri, MMAL_ES_FORMAT_T *format, MMAL_STATUS_T *p_status)
1330{
1331 VC_CONTAINER_T *container = 0;
1332 VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FAILED;
1333 VC_CONTAINER_ES_FORMAT_T *container_format = 0;
1334
1335 /* Open container */
1336 container = vc_container_open_writer(uri, &status, 0, 0);
1337 if(status != VC_CONTAINER_SUCCESS)
1338 {
1339 LOG_ERROR("error opening uri %s (%i)", uri, status);
1340 goto error;
1341 }
1342
1343 /* Set format from MMAL port format */
1344 container_format = vc_container_format_create(0);
1345 if (!container_format)
1346 {
1347 status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
1348 LOG_ERROR("error (%i)", status);
1349 goto error;
1350 }
1351
1352 switch (format->type)
1353 {
1354 case MMAL_ES_TYPE_VIDEO:
1355 container_format->es_type = VC_CONTAINER_ES_TYPE_VIDEO;
1356 break;
1357 default:
1358 status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
1359 LOG_ERROR("unsupported elementary stream format error (%i)", status);
1360 goto error;
1361 }
1362
1363 container_format->codec = test_container_encoding_to_codec(format->encoding);
1364 if(format->encoding == MMAL_ENCODING_H264)
1365 container_format->codec_variant = VC_FOURCC('a','v','c','C');
1366 container_format->type->video.width = format->es->video.width;
1367 container_format->type->video.height = format->es->video.height;
1368 container_format->type->video.frame_rate_num = format->es->video.frame_rate.num;
1369 container_format->type->video.frame_rate_den = format->es->video.frame_rate.den;
1370 container_format->type->video.par_num = format->es->video.par.num;
1371 container_format->type->video.par_den = format->es->video.par.den;
1372 container_format->bitrate = format->bitrate;
1373 container_format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
1374
1375 container_format->extradata_size = 0;
1376
1377 status = vc_container_control(container, VC_CONTAINER_CONTROL_TRACK_ADD, container_format);
1378 if(status != VC_CONTAINER_SUCCESS)
1379 {
1380 LOG_ERROR("error adding track (%i)", status);
1381 goto error;
1382 }
1383
1384 vc_container_control(container, VC_CONTAINER_CONTROL_TRACK_ADD_DONE);
1385
1386end:
1387 if (container_format)
1388 vc_container_format_delete(container_format);
1389 if (p_status) *p_status = test_container_to_mmal_status(status);
1390 return container;
1391error:
1392 if (container)
1393 {
1394 vc_container_close(container);
1395 container = 0;
1396 }
1397 goto end;
1398}
1399
1400/*****************************************************************************/
1401static MMAL_STATUS_T test_container_write(VC_CONTAINER_T *container, MMAL_BUFFER_HEADER_T *buffer)
1402{
1403 VC_CONTAINER_PACKET_T packet;
1404 VC_CONTAINER_STATUS_T status;
1405 memset(&packet, 0, sizeof(packet));
1406 static int first_fragment = 1;
1407
1408#if 0
1409 if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_CONFIG)
1410 buffer->length = 0; /* Discard codec config data arriving in buffers */
1411#endif
1412
1413 if (buffer->length == 0)
1414 return MMAL_SUCCESS;
1415
1416 packet.track = 0;
1417 packet.pts = buffer->pts == MMAL_TIME_UNKNOWN ? VC_CONTAINER_TIME_UNKNOWN : buffer->pts;
1418 packet.dts = buffer->dts == MMAL_TIME_UNKNOWN ? VC_CONTAINER_TIME_UNKNOWN : buffer->dts;
1419 if(buffer->flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
1420 packet.flags |= VC_CONTAINER_PACKET_FLAG_KEYFRAME;
1421 if(first_fragment || (buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_START))
1422 {
1423 packet.flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
1424 first_fragment = 0;
1425 }
1426
1427 if(buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END)
1428 {
1429 packet.flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
1430 first_fragment = 1; /* Next buffer will be the first fragment */
1431 }
1432
1433 packet.size = packet.buffer_size = buffer->length;
1434 if ((packet.flags & VC_CONTAINER_PACKET_FLAG_FRAME) == VC_CONTAINER_PACKET_FLAG_FRAME)
1435 packet.frame_size = packet.size;
1436
1437 vcos_assert(buffer->offset == 0);
1438
1439 packet.data = buffer->data;
1440
1441 LOG_DEBUG("writing packet: track %i, size %i/%i, pts %"PRId64", flags %x%s",
1442 packet.track, packet.size, packet.frame_size, packet.pts,
1443 packet.flags, (packet.flags & VC_CONTAINER_PACKET_FLAG_KEYFRAME) ? " (keyframe)" : "");
1444
1445 status = vc_container_write(container, &packet);
1446
1447 return test_container_to_mmal_status(status);
1448}
1449
1450/*****************************************************************************/
1451static struct {
1452 VC_CONTAINER_FOURCC_T codec;
1453 uint32_t encoding;
1454} codec_to_encoding_table[] =
1455{
1456 {VC_CONTAINER_CODEC_H263, MMAL_ENCODING_H263},
1457 {VC_CONTAINER_CODEC_H264, MMAL_ENCODING_H264},
1458 {VC_CONTAINER_CODEC_MP4V, MMAL_ENCODING_MP4V},
1459 {VC_CONTAINER_CODEC_MP2V, MMAL_ENCODING_MP2V},
1460 {VC_CONTAINER_CODEC_MP1V, MMAL_ENCODING_MP1V},
1461 {VC_CONTAINER_CODEC_WMV3, MMAL_ENCODING_WMV3},
1462 {VC_CONTAINER_CODEC_WMV2, MMAL_ENCODING_WMV2},
1463 {VC_CONTAINER_CODEC_WMV1, MMAL_ENCODING_WMV1},
1464 {VC_CONTAINER_CODEC_WVC1, MMAL_ENCODING_WVC1},
1465 {VC_CONTAINER_CODEC_VP6, MMAL_ENCODING_VP6},
1466 {VC_CONTAINER_CODEC_VP7, MMAL_ENCODING_VP7},
1467 {VC_CONTAINER_CODEC_VP8, MMAL_ENCODING_VP8},
1468 {VC_CONTAINER_CODEC_THEORA, MMAL_ENCODING_THEORA},
1469 {VC_CONTAINER_CODEC_UNKNOWN, MMAL_ENCODING_UNKNOWN}
1470};
1471
1472static VC_CONTAINER_FOURCC_T test_container_encoding_to_codec(uint32_t encoding)
1473{
1474 unsigned int i;
1475 for(i = 0; codec_to_encoding_table[i].codec != VC_CONTAINER_CODEC_UNKNOWN; i++)
1476 if(codec_to_encoding_table[i].encoding == encoding) break;
1477 return codec_to_encoding_table[i].codec;
1478}
1479#endif
1480