/* Connect two mmal components which will transer data via an ARM callback. | A components output data may be processed or altered before being | passed to a components input port. The camera out object will be passed | as userdata to the callback as it must have the callback_port_in and | callback_pool_in values. */ boolean ports_callback_connect(CameraObject *out, int port_num, CameraObject *in, void callback()) { MMAL_PORT_T *callback_port_in; MMAL_STATUS_T status; boolean result; if (!out->component || !in->component) return FALSE; callback_port_in = in->component->input[0]; /* Create the buffer pool and queue for the input port the callback | will send buffers to after processing. Input port is likely an encoder. */ out->callback_port_in = callback_port_in; out->callback_pool_in = mmal_port_pool_create(callback_port_in, callback_port_in->buffer_num, callback_port_in->buffer_size); if ((status = mmal_port_enable(callback_port_in, input_buffer_callback)) != MMAL_SUCCESS) { log_printf( "ports_callback_connect %s: mmal_port_enable failed. Status %s\n", in->name, mmal_status[status]); result = FALSE; } else result = out_port_callback(out, port_num, callback); return result; }
void camera_start(void) { MMAL_STATUS_T status; motion_init(); circular_buffer_init(); camera_create(); /* ====== Create the camera preview port path ====== : | preview --(tunnel)--> resizer --> I420_callback --> jpeg_encoder --> mjpeg_callback | (draws on frame) (writes stream mjpeg.jpg) */ pikrellcam.mjpeg_height = pikrellcam.mjpeg_width * pikrellcam.camera_config.video_height / pikrellcam.camera_config.video_width; pikrellcam.mjpeg_width &= ~0xf; /* Make resize multiple of 16 */ pikrellcam.mjpeg_height &= ~0xf; resizer_create("stream_resizer", &stream_resizer, camera.component->output[CAMERA_PREVIEW_PORT], pikrellcam.mjpeg_width, pikrellcam.mjpeg_height); ports_tunnel_connect(&camera, CAMERA_PREVIEW_PORT, &stream_resizer); jpeg_encoder_create("mjpeg_encoder", &mjpeg_encoder, stream_resizer.component->output[0], pikrellcam.mjpeg_quality); ports_callback_connect(&stream_resizer, 0, &mjpeg_encoder, I420_video_callback); out_port_callback(&mjpeg_encoder, 0, mjpeg_callback); /* ====== Create the camera still port path ====== : | camera_capture --(tunnel)--> jpeg_encoder --> still_jpeg__callback | (writes stills and timelapse jpegs) */ jpeg_encoder_create("still_jpeg_encoder", &still_jpeg_encoder, NULL, pikrellcam.camera_adjust.still_quality); ports_tunnel_connect(&camera, CAMERA_CAPTURE_PORT, &still_jpeg_encoder); out_port_callback(&still_jpeg_encoder, 0, still_jpeg_callback); /* ====== Create the camera video port path ====== : | camera_video--(tunnel)-->h264 encoder-->video_h264_encoder_callback | (writes data into video circular buffer) | (records video / checks motion vectors) | (schedules mjpeg.jpg copy into previews) */ h264_encoder_create("video_h264_encoder", &video_h264_encoder, NULL); ports_tunnel_connect(&camera, CAMERA_VIDEO_PORT, &video_h264_encoder); out_port_callback(&video_h264_encoder, 0, video_h264_encoder_callback); time(&pikrellcam.t_start); /* Turn on the video stream. It free runs into the video circular buffer. */ if ((status = mmal_port_parameter_set_boolean( camera.component->output[CAMERA_VIDEO_PORT], MMAL_PARAMETER_CAPTURE, 1)) != MMAL_SUCCESS) log_printf("Video capture startup failed. Status %s\n", mmal_status[status]); /* With everything created and running, set the config'ed camera params. */ mmalcam_config_parameters_set_camera(); display_init(); video_circular_buffer.state = VCB_STATE_NONE; video_circular_buffer.pause = FALSE; }