/** * buffer header callback function for camera control * * Callback will dump buffer data to the specific file * * @param port Pointer to port from which callback originated * @param buffer mmal buffer header pointer */ static void camera_control_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { if (buffer->cmd == MMAL_EVENT_PARAMETER_CHANGED) { } else { vcos_log_error("Received unexpected camera control callback event, 0x%08x", buffer->cmd); } mmal_buffer_header_release(buffer); }
/** Check for OpenGL errors - logs any errors and sets quit flag */ static void vidtex_check_gl(VIDTEX_T *vt, uint32_t line) { GLenum error = glGetError(); int abort = 0; while (error != GL_NO_ERROR) { vcos_log_error("GL error: line %d error 0x%04x", line, error); abort = 1; error = glGetError(); } if (abort) vidtex_stop_cb(vt, SVP_STOP_ERROR); }
/* Initialises GL preview state and creates the dispmanx native window. * @param state Pointer to the GL preview state. * @return Zero if successful. */ int raspitex_init(RASPITEX_STATE *state) { VCOS_STATUS_T status; int rc; vcos_init(); vcos_log_register("RaspiTex", VCOS_LOG_CATEGORY); vcos_log_set_level(VCOS_LOG_CATEGORY, state->verbose ? VCOS_LOG_INFO : VCOS_LOG_WARN); vcos_log_trace("%s", VCOS_FUNCTION); status = vcos_semaphore_create(&state->capture.start_sem, "glcap_start_sem", 1); if (status != VCOS_SUCCESS) goto error; status = vcos_semaphore_create(&state->capture.completed_sem, "glcap_completed_sem", 0); if (status != VCOS_SUCCESS) goto error; switch (state->scene_id) { case RASPITEX_SCENE_SQUARE: rc = square_open(state); break; case RASPITEX_SCENE_MIRROR: rc = mirror_open(state); break; case RASPITEX_SCENE_TEAPOT: rc = teapot_open(state); break; case RASPITEX_SCENE_YUV: rc = yuv_open(state); break; case RASPITEX_SCENE_SOBEL: rc = sobel_open(state); break; default: rc = -1; break; } if (rc != 0) goto error; return 0; error: vcos_log_error("%s: failed", VCOS_FUNCTION); return -1; }
MMAL_STATUS_T raspipreview_create( RASPIPREVIEW_PARAMETERS *state ) { MMAL_COMPONENT_T *preview = 0; MMAL_PORT_T *preview_port = NULL; MMAL_STATUS_T status; // No preview required, so create a null sink component to take its place status = mmal_component_create("vc.null_sink", &preview); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to create null sink component"); goto error; } /* Enable component */ status = mmal_component_enable(preview); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to enable preview/null sink component (%u)", status); goto error; } state->preview_component = preview; return status; error: if (preview) mmal_component_destroy(preview); return status; }
VCOS_STATUS_T vcos_log_assert_cmd( VCOS_CMD_PARAM_T *param ) { (void)param; #if defined( NDEBUG ) && !defined( VCOS_RELEASE_ASSERTS ) vcos_log_error( "vcos_asserts have been compiled out" ); vcos_cmd_printf( param, "vcos_asserts have been compiled out - did a vcos_log_error instead\n" ); #else vcos_assert(0); vcos_cmd_printf( param, "Executed vcos_assert(0)\n" ); #endif return VCOS_SUCCESS; }
/** * Starts the worker / GL renderer thread. * @pre raspitex_init was successful * @pre raspitex_configure_preview_port was successful * @param state Pointer to the GL preview state. * @return Zero on success, otherwise, -1 is returned * */ int raspitex_start(RASPITEX_STATE *state) { VCOS_STATUS_T status; vcos_log_trace("%s", VCOS_FUNCTION); status = vcos_thread_create(&state->preview_thread, "preview-worker", NULL, preview_worker, state); if (status != VCOS_SUCCESS) vcos_log_error("%s: Failed to start worker thread %d", VCOS_FUNCTION, status); return (status == VCOS_SUCCESS ? 0 : -1); }
/** * Handler for sigint signals * * @param signal_number ID of incoming signal. * */ static void signal_handler(int signal_number) { if (signal_number == SIGUSR1) { // Handle but ignore - prevents us dropping out if started in none-signal mode // and someone sends us the USR1 signal anyway } else { // Going to abort on all other signals vcos_log_error("Aborting program\n"); exit(130); } }
/** * Connect two specific ports together * * @param output_port Pointer the output port * @param input_port Pointer the input port * @param Pointer to a mmal connection pointer, reassigned if function successful * @return Returns a MMAL_STATUS_T giving result of operation * */ static MMAL_STATUS_T connect_ports(MMAL_PORT_T *output_port, MMAL_PORT_T *input_port, MMAL_CONNECTION_T **connection) { MMAL_STATUS_T status; status = mmal_connection_create(connection, output_port, input_port, MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT); if (status == MMAL_SUCCESS) { status = mmal_connection_enable(*connection); if (status != MMAL_SUCCESS) { vcos_log_error("Failed to connect ports %s and %s - status %d", output_port->name, input_port->name); mmal_connection_destroy(*connection); } } return status; }
/** * Writes the next GL frame-buffer to a RAW .ppm formatted file * using the specified file-handle. * @param state Pointer to the GL preview state. * @param outpt_file Output file handle for the ppm image. * @return Zero on success. */ int raspitex_capture(RASPITEX_STATE *state, FILE *output_file) { int rc = 0; uint8_t *buffer = NULL; size_t size = 0; vcos_log_trace("%s: state %p file %p", VCOS_FUNCTION, state, output_file); if (state && output_file) { /* Only request one capture at a time */ vcos_semaphore_wait(&state->capture.start_sem); state->capture.request = 1; /* Wait for capture to start */ vcos_semaphore_wait(&state->capture.completed_sem); /* Take ownership of the captured buffer */ buffer = state->capture.buffer; size = state->capture.size; state->capture.request = 0; state->capture.buffer = 0; state->capture.size = 0; /* Allow another capture to be requested */ vcos_semaphore_post(&state->capture.start_sem); } if (size == 0 || ! buffer) { vcos_log_error("%s: capture failed", VCOS_FUNCTION); rc = -1; goto end; } raspitexutil_brga_to_rgba(buffer, size); rc = write_tga(output_file, state->width, state->height, buffer, size); fflush(output_file); end: free(buffer); return rc; }
static int preview_process_returned_bufs(RASPITEX_STATE* state) { MMAL_BUFFER_HEADER_T *buf; int rc = 0; while ((buf = mmal_queue_get(state->preview_queue)) != NULL) { if (state->preview_stop == 0) { if (state->m_nGetData) { rc = raspitex_draw(state, buf); // block complete chain!!! if (rc != 0) { vcos_log_error("%s: Error drawing frame. Stopping.", VCOS_FUNCTION); state->preview_stop = 1; return rc; } } else { //Now return the PREVIOUS MMAL buffer header back to the camera preview. if (state->preview_buf) mmal_buffer_header_release(state->preview_buf); state->preview_buf = buf; } } } /* If there were no new frames then redraw the scene again with the previous * texture. Otherwise, go round the loop again to see if any new buffers * are returned. */ /*if (! new_frame) { //vcos_log_info("%s: no new frame - redraw previous.", VCOS_FUNCTION); rc = raspitex_draw(state, NULL); }*/ return rc; }
/** * Set the contrast adjustment for the image * @param camera Pointer to camera component * @param contrast Contrast adjustment -100 to 100 * @return */ int raspicamcontrol_set_contrast(MMAL_COMPONENT_T *camera, int contrast) { int ret = 0; if (!camera) return 1; if (contrast >= -100 && contrast <= 100) { MMAL_RATIONAL_T value = {contrast, 100}; ret = mmal_status_to_int(mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_CONTRAST, value)); } else { vcos_log_error("Invalid contrast value"); ret = 1; } return ret; }
/** * Set the sharpness of the image * @param camera Pointer to camera component * @param sharpness Sharpness adjustment -100 to 100 */ int raspicamcontrol_set_sharpness(MMAL_COMPONENT_T *camera, int sharpness) { int ret = 0; if (!camera) return 1; if (sharpness >= -100 && sharpness <= 100) { MMAL_RATIONAL_T value = {sharpness, 100}; ret = mmal_status_to_int(mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_SHARPNESS, value)); } else { vcos_log_error("Invalid sharpness value"); ret = 1; } return ret; }
/** * Adjust the saturation level for images * @param camera Pointer to camera component * @param saturation Value to adjust, -100 to 100 * @return 0 if successful, non-zero if any parameters out of range */ int raspicamcontrol_set_saturation(MMAL_COMPONENT_T *camera, int saturation) { int ret = 0; if (!camera) return 1; if (saturation >= -100 && saturation <= 100) { MMAL_RATIONAL_T value = {saturation, 100}; ret = mmal_status_to_int(mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_SATURATION, value)); } else { vcos_log_error("Invalid saturation value"); ret = 1; } return ret; }
/** * Adjust the brightness level for images * @param camera Pointer to camera component * @param brightness Value to adjust, 0 to 100 * @return 0 if successful, non-zero if any parameters out of range */ int raspicamcontrol_set_brightness(MMAL_COMPONENT_T *camera, int brightness) { int ret = 0; if (!camera) return 1; if (brightness >= 0 && brightness <= 100) { MMAL_RATIONAL_T value = {brightness, 100}; ret = mmal_status_to_int(mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_BRIGHTNESS, value)); } else { vcos_log_error("Invalid brightness value"); ret = 1; } return ret; }
/** * Create the camera component, set up its ports * * @param state Pointer to state control struct. camera_component member set to the created camera_component if successfull. * * @return MMAL_SUCCESS if all OK, something else otherwise * */ static MMAL_STATUS_T create_camera_component(RASPISTILL_STATE *state) { MMAL_COMPONENT_T *camera = 0; MMAL_ES_FORMAT_T *format; MMAL_PORT_T *preview_port = NULL, *video_port = NULL, *still_port = NULL; MMAL_STATUS_T status; /* Create the component */ status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera); if (status != MMAL_SUCCESS) { vcos_log_error("Failed to create camera component"); goto error; } if (!camera->output_num) { status = MMAL_ENOSYS; vcos_log_error("Camera doesn't have output ports"); goto error; } preview_port = camera->output[MMAL_CAMERA_PREVIEW_PORT]; video_port = camera->output[MMAL_CAMERA_VIDEO_PORT]; still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT]; // Enable the camera, and tell it its control callback function status = mmal_port_enable(camera->control, camera_control_callback); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to enable control port : error %d", status); goto error; } // set up the camera configuration { MMAL_PARAMETER_CAMERA_CONFIG_T cam_config = { { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) }, .max_stills_w = state->width, .max_stills_h = state->height, .stills_yuv422 = 0, .one_shot_stills = 1, .max_preview_video_w = state->preview_parameters.previewWindow.width, .max_preview_video_h = state->preview_parameters.previewWindow.height, .num_preview_video_frames = 3, .stills_capture_circular_buffer_height = 0, .fast_preview_resume = 0, .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RESET_STC }; if (state->fullResPreview) { cam_config.max_preview_video_w = state->width; cam_config.max_preview_video_h = state->height; } mmal_port_parameter_set(camera->control, &cam_config.hdr); } raspicamcontrol_set_all_parameters(camera, &state->camera_parameters); // Now set up the port formats format = preview_port->format; format->encoding = MMAL_ENCODING_OPAQUE; format->encoding_variant = MMAL_ENCODING_I420; if (state->fullResPreview) { // In this mode we are forcing the preview to be generated from the full capture resolution. // This runs at a max of 15fps with the OV5647 sensor. format->es->video.width = state->width; format->es->video.height = state->height; format->es->video.crop.x = 0; format->es->video.crop.y = 0; format->es->video.crop.width = state->width; format->es->video.crop.height = state->height; format->es->video.frame_rate.num = FULL_RES_PREVIEW_FRAME_RATE_NUM; format->es->video.frame_rate.den = FULL_RES_PREVIEW_FRAME_RATE_DEN; } else { // use our normal preview mode - probably 1080p30 format->es->video.width = state->preview_parameters.previewWindow.width; format->es->video.height = state->preview_parameters.previewWindow.height; format->es->video.crop.x = 0; format->es->video.crop.y = 0; format->es->video.crop.width = state->preview_parameters.previewWindow.width; format->es->video.crop.height = state->preview_parameters.previewWindow.height; format->es->video.frame_rate.num = PREVIEW_FRAME_RATE_NUM; format->es->video.frame_rate.den = PREVIEW_FRAME_RATE_DEN; } status = mmal_port_format_commit(preview_port); if (status != MMAL_SUCCESS) { vcos_log_error("camera viewfinder format couldn't be set"); goto error; } // Set the same format on the video port (which we dont use here) mmal_format_full_copy(video_port->format, format); status = mmal_port_format_commit(video_port); if (status != MMAL_SUCCESS) { vcos_log_error("camera video format couldn't be set"); goto error; } // Ensure there are enough buffers to avoid dropping frames if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM) video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM; format = still_port->format; // Set our stills format on the stills (for encoder) port format->encoding = MMAL_ENCODING_OPAQUE; format->es->video.width = state->width; format->es->video.height = state->height; format->es->video.crop.x = 0; format->es->video.crop.y = 0; format->es->video.crop.width = state->width; format->es->video.crop.height = state->height; format->es->video.frame_rate.num = STILLS_FRAME_RATE_NUM; format->es->video.frame_rate.den = STILLS_FRAME_RATE_DEN; status = mmal_port_format_commit(still_port); if (status != MMAL_SUCCESS) { vcos_log_error("camera still format couldn't be set"); goto error; } /* Ensure there are enough buffers to avoid dropping frames */ if (still_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM) still_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM; /* Enable component */ status = mmal_component_enable(camera); if (status != MMAL_SUCCESS) { vcos_log_error("camera component couldn't be enabled"); goto error; } state->camera_component = camera; if (state->verbose) fprintf(stderr, "Camera component done\n"); return status; error: if (camera) mmal_component_destroy(camera); return status; }
/** * Create the camera component, set up its ports * * @param state Pointer to state control struct * * @return 0 if failed, pointer to component if successful * */ static MMAL_COMPONENT_T *create_camera_component(RASPISTILLYUV_STATE *state) { MMAL_COMPONENT_T *camera = 0; MMAL_ES_FORMAT_T *format; MMAL_PORT_T *preview_port = NULL, *video_port = NULL, *still_port = NULL; MMAL_STATUS_T status; MMAL_POOL_T *pool; /* Create the component */ status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera); if (status != MMAL_SUCCESS) { vcos_log_error("Failed to create camera component"); goto error; } if (!camera->output_num) { vcos_log_error("Camera doesn't have output ports"); goto error; } preview_port = camera->output[MMAL_CAMERA_PREVIEW_PORT]; video_port = camera->output[MMAL_CAMERA_VIDEO_PORT]; still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT]; // Enable the camera, and tell it its control callback function status = mmal_port_enable(camera->control, camera_control_callback); if (status) { vcos_log_error("Unable to enable control port : error %d", status); goto error; } // set up the camera configuration { MMAL_PARAMETER_CAMERA_CONFIG_T cam_config = { { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) }, .max_stills_w = state->width, .max_stills_h = state->height, .stills_yuv422 = 0, .one_shot_stills = 0, .max_preview_video_w = state->preview_parameters.previewWindow.width, .max_preview_video_h = state->preview_parameters.previewWindow.height, .num_preview_video_frames = 3, .stills_capture_circular_buffer_height = 0, .fast_preview_resume = 0, .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RESET_STC }; mmal_port_parameter_set(camera->control, &cam_config.hdr); } raspicamcontrol_set_all_parameters(camera, &state->camera_parameters); // Now set up the port formats format = preview_port->format; format->encoding = MMAL_ENCODING_OPAQUE; format->encoding_variant = MMAL_ENCODING_I420; format->es->video.width = state->preview_parameters.previewWindow.width; format->es->video.height = state->preview_parameters.previewWindow.height; format->es->video.crop.x = 0; format->es->video.crop.y = 0; format->es->video.crop.width = state->preview_parameters.previewWindow.width; format->es->video.crop.height = state->preview_parameters.previewWindow.height; format->es->video.frame_rate.num = PREVIEW_FRAME_RATE_NUM; format->es->video.frame_rate.den = PREVIEW_FRAME_RATE_DEN; status = mmal_port_format_commit(preview_port); if (status) { vcos_log_error("camera viewfinder format couldn't be set"); goto error; } // Set the same format on the video port (which we dont use here) mmal_format_full_copy(video_port->format, format); status = mmal_port_format_commit(video_port); if (status) { vcos_log_error("camera video format couldn't be set"); goto error; } // Ensure there are enough buffers to avoid dropping frames if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM) video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM; format = still_port->format; // Set our stills format on the stills port format->encoding = MMAL_ENCODING_I420; format->encoding_variant = MMAL_ENCODING_I420; format->es->video.width = state->width; format->es->video.height = state->height; format->es->video.crop.x = 0; format->es->video.crop.y = 0; format->es->video.crop.width = state->width; format->es->video.crop.height = state->height; format->es->video.frame_rate.num = STILLS_FRAME_RATE_NUM; format->es->video.frame_rate.den = STILLS_FRAME_RATE_DEN; if (still_port->buffer_size < still_port->buffer_size_min) still_port->buffer_size = still_port->buffer_size_min; still_port->buffer_num = still_port->buffer_num_recommended; status = mmal_port_format_commit(still_port); if (status) { vcos_log_error("camera still format couldn't be set"); goto error; } /* Enable component */ status = mmal_component_enable(camera); if (status) { vcos_log_error("camera component couldn't be enabled"); goto error; } /* Create pool of buffer headers for the output port to consume */ pool = mmal_port_pool_create(still_port, still_port->buffer_num, still_port->buffer_size); if (!pool) { vcos_log_error("Failed to create buffer header pool for camera still port %s", still_port->name); } state->camera_pool = pool; state->camera_component = camera; if (state->verbose) printf("Camera component done\n"); return camera; error: if (camera) mmal_component_destroy(camera); return 0; }
/** * main */ int main(int argc, const char **argv) { // Our main data storage vessel.. RASPISTILLYUV_STATE state; MMAL_STATUS_T status; MMAL_PORT_T *camera_preview_port = NULL; MMAL_PORT_T *camera_video_port = NULL; MMAL_PORT_T *camera_still_port = NULL; MMAL_PORT_T *preview_input_port = NULL; FILE *output_file = NULL; // Register our application with the logging system vcos_log_register("RaspiStill", VCOS_LOG_CATEGORY); printf("\nRaspiStillYUV Camera App\n"); printf( "========================\n\n"); signal(SIGINT, signal_handler); // Do we have any parameters if (argc == 1) { display_valid_parameters(); exit(0); } default_status(&state); // Parse the command line and put options in to our status structure if (parse_cmdline(argc, argv, &state)) { status = -1; exit(0); } if (state.verbose) dump_status(&state); // OK, we have a nice set of parameters. Now set up our components // We have two components. Camera and Preview // Camera is different in stills/video, but preview // is the same so handed off to a separate module if (!create_camera_component(&state)) { vcos_log_error("%s: Failed to create camera component", __func__); } else if ( !raspipreview_create(&state.preview_parameters)) { vcos_log_error("%s: Failed to create preview component", __func__); destroy_camera_component(&state); } else { PORT_USERDATA callback_data; if (state.verbose) printf("Starting component connection stage\n"); camera_preview_port = state.camera_component->output[MMAL_CAMERA_PREVIEW_PORT]; camera_video_port = state.camera_component->output[MMAL_CAMERA_VIDEO_PORT]; camera_still_port = state.camera_component->output[MMAL_CAMERA_CAPTURE_PORT]; preview_input_port = state.preview_parameters.preview_component->input[0]; if (state.preview_parameters.wantPreview ) { if (state.verbose) { printf("Connecting camera preview port to preview input port\n"); printf("Starting video preview\n"); } // Connect camera to preview status = connect_ports(camera_preview_port, preview_input_port, &state.preview_connection); } if (status == MMAL_SUCCESS) { VCOS_STATUS_T vcos_status; if (state.filename) { if (state.verbose) printf("Opening output file %s\n", state.filename); output_file = fopen(state.filename, "wb"); if (!output_file) { // Notify user, carry on but discarding encoded output buffers vcos_log_error("%s: Error opening output file: %s\nNo output file will be generated\n", __func__, state.filename); } } // Set up our userdata - this is passed though to the callback where we need the information. callback_data.file_handle = output_file; callback_data.pstate = &state; vcos_status = vcos_semaphore_create(&callback_data.complete_semaphore, "RaspiStill-sem", 0); vcos_assert(vcos_status == VCOS_SUCCESS); camera_still_port->userdata = (struct MMAL_PORT_USERDATA_T *)&callback_data; if (state.verbose) printf("Enabling camera still output port\n"); // Enable the camera still output port and tell it its callback function status = mmal_port_enable(camera_still_port, camera_buffer_callback); if (status != MMAL_SUCCESS) { vcos_log_error("Failed to setup camera output"); goto error; } if (state.verbose) printf("Starting video preview\n"); // Send all the buffers to the encoder output port { int num = mmal_queue_length(state.camera_pool->queue); int q; for (q=0;q<num;q++) { MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state.camera_pool->queue); if (!buffer) vcos_log_error("Unable to get a required buffer %d from pool queue", q); if (mmal_port_send_buffer(camera_still_port, buffer)!= MMAL_SUCCESS) vcos_log_error("Unable to send a buffer to encoder output port (%d)", q); } } // Now wait until we need to do the capture vcos_sleep(state.timeout); // And only do the capture if we have specified a filename and its opened OK if (output_file) { if (state.verbose) printf("Starting capture\n"); // Fire the capture if (mmal_port_parameter_set_boolean(camera_still_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to start capture", __func__); } else { // Wait for capture to complete // For some reason using vcos_semaphore_wait_timeout sometimes returns immediately with bad parameter error // even though it appears to be all correct, so reverting to untimed one until figure out why its erratic vcos_semaphore_wait(&callback_data.complete_semaphore); if (state.verbose) printf("Finished capture\n"); } } vcos_semaphore_delete(&callback_data.complete_semaphore); } else { mmal_status_to_int(status); vcos_log_error("%s: Failed to connect camera to preview", __func__); } error: mmal_status_to_int(status); if (state.verbose) printf("Closing down\n"); if (output_file) fclose(output_file); // Disable all our ports that are not handled by connections check_disable_port(camera_video_port); if (state.preview_parameters.wantPreview ) mmal_connection_destroy(state.preview_connection); /* Disable components */ if (state.preview_parameters.preview_component) mmal_component_disable(state.preview_parameters.preview_component); if (state.camera_component) mmal_component_disable(state.camera_component); raspipreview_destroy(&state.preview_parameters); destroy_camera_component(&state); if (state.verbose) printf("Close down completed, all components disconnected, disabled and destroyed\n\n"); } return 0; }
/** * Create the camera component, set up its ports * * @param state Pointer to state control struct * * @return 0 if failed, pointer to component if successful * */ static MMAL_COMPONENT_T *create_camera_component(RASPIVID_STATE *state) { MMAL_COMPONENT_T *camera = 0; MMAL_ES_FORMAT_T *format; MMAL_PORT_T *preview_port = NULL, *video_port = NULL, *still_port = NULL; MMAL_STATUS_T status; /* Create the component */ status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera); if (status != MMAL_SUCCESS) { vcos_log_error("Failed to create camera component"); goto error; } if (!camera->output_num) { vcos_log_error("Camera doesn't have output ports"); goto error; } video_port = camera->output[MMAL_CAMERA_VIDEO_PORT]; still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT]; // set up the camera configuration { MMAL_PARAMETER_CAMERA_CONFIG_T cam_config = { { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) }, .max_stills_w = state->width, .max_stills_h = state->height, .stills_yuv422 = 0, .one_shot_stills = 0, .max_preview_video_w = state->width, .max_preview_video_h = state->height, .num_preview_video_frames = 3, .stills_capture_circular_buffer_height = 0, .fast_preview_resume = 0, .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RESET_STC }; mmal_port_parameter_set(camera->control, &cam_config.hdr); } // Set the encode format on the video port format = video_port->format; format->encoding_variant = MMAL_ENCODING_I420; format->encoding = MMAL_ENCODING_I420; format->es->video.width = state->width; format->es->video.height = state->height; format->es->video.crop.x = 0; format->es->video.crop.y = 0; format->es->video.crop.width = state->width; format->es->video.crop.height = state->height; format->es->video.frame_rate.num = state->framerate; format->es->video.frame_rate.den = VIDEO_FRAME_RATE_DEN; status = mmal_port_format_commit(video_port); if (status) { vcos_log_error("camera video format couldn't be set"); goto error; } // PR : plug the callback to the video port status = mmal_port_enable(video_port, video_buffer_callback); if (status) { vcos_log_error("camera video callback2 error"); goto error; } // Ensure there are enough buffers to avoid dropping frames if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM) video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM; // Set the encode format on the still port format = still_port->format; format->encoding = MMAL_ENCODING_OPAQUE; format->encoding_variant = MMAL_ENCODING_I420; format->es->video.width = state->width; format->es->video.height = state->height; format->es->video.crop.x = 0; format->es->video.crop.y = 0; format->es->video.crop.width = state->width; format->es->video.crop.height = state->height; format->es->video.frame_rate.num = 1; format->es->video.frame_rate.den = 1; status = mmal_port_format_commit(still_port); if (status) { vcos_log_error("camera still format couldn't be set"); goto error; } //PR : create pool of message on video port MMAL_POOL_T *pool; video_port->buffer_size = video_port->buffer_size_recommended; video_port->buffer_num = video_port->buffer_num_recommended; pool = mmal_port_pool_create(video_port, video_port->buffer_num, video_port->buffer_size); if (!pool) { vcos_log_error("Failed to create buffer header pool for video output port"); } state->video_pool = pool; /* Ensure there are enough buffers to avoid dropping frames */ if (still_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM) still_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM; /* Enable component */ status = mmal_component_enable(camera); if (status) { vcos_log_error("camera component couldn't be enabled"); goto error; } raspicamcontrol_set_all_parameters(camera, &state->camera_parameters); state->camera_component = camera; return camera; error: if (camera) mmal_component_destroy(camera); return 0; }
RaspiCamCvCapture * raspiCamCvCreateCameraCapture(int index) { RaspiCamCvCapture * capture = (RaspiCamCvCapture*)malloc(sizeof(RaspiCamCvCapture)); // Our main data storage vessel.. RASPIVID_STATE * state = (RASPIVID_STATE*)malloc(sizeof(RASPIVID_STATE)); capture->pState = state; MMAL_STATUS_T status = -1; MMAL_PORT_T *camera_video_port = NULL; MMAL_PORT_T *camera_still_port = NULL; bcm_host_init(); // read default status default_status(state); int w = state->width; int h = state->height; state->py = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1); // Y component of YUV I420 frame if (state->graymode==0) { state->pu = cvCreateImage(cvSize(w/2,h/2), IPL_DEPTH_8U, 1); // U component of YUV I420 frame state->pv = cvCreateImage(cvSize(w/2,h/2), IPL_DEPTH_8U, 1); // V component of YUV I420 frame } vcos_semaphore_create(&state->capture_sem, "Capture-Sem", 0); vcos_semaphore_create(&state->capture_done_sem, "Capture-Done-Sem", 0); if (state->graymode==0) { state->pu_big = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1); state->pv_big = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1); state->yuvImage = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 3); state->dstImage = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 3); // final picture to display } // create camera if (!create_camera_component(state)) { vcos_log_error("%s: Failed to create camera component", __func__); raspiCamCvReleaseCapture(&capture); return NULL; } camera_video_port = state->camera_component->output[MMAL_CAMERA_VIDEO_PORT]; camera_still_port = state->camera_component->output[MMAL_CAMERA_CAPTURE_PORT]; // assign data to use for callback camera_video_port->userdata = (struct MMAL_PORT_USERDATA_T *)state; // start capture if (mmal_port_parameter_set_boolean(camera_video_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to start capture", __func__); raspiCamCvReleaseCapture(&capture); return NULL; } // Send all the buffers to the video port int num = mmal_queue_length(state->video_pool->queue); int q; for (q = 0; q < num; q++) { MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state->video_pool->queue); if (!buffer) vcos_log_error("Unable to get a required buffer %d from pool queue", q); if (mmal_port_send_buffer(camera_video_port, buffer)!= MMAL_SUCCESS) vcos_log_error("Unable to send a buffer to encoder output port (%d)", q); } //mmal_status_to_int(status); // Disable all our ports that are not handled by connections //check_disable_port(camera_still_port); //if (status != 0) // raspicamcontrol_check_configuration(128); vcos_semaphore_wait(&state->capture_done_sem); return capture; }
/** * buffer header callback function for video * * @param port Pointer to port from which callback originated * @param buffer mmal buffer header pointer */ static void video_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { MMAL_BUFFER_HEADER_T *new_buffer; RASPIVID_STATE * state = (RASPIVID_STATE *)port->userdata; if (state) { if (state->finished) { vcos_semaphore_post(&state->capture_done_sem); return; } if (buffer->length) { mmal_buffer_header_mem_lock(buffer); // // *** PR : OPEN CV Stuff here ! // int w=state->width; // get image size int h=state->height; int h4=h/4; memcpy(state->py->imageData,buffer->data,w*h); // read Y if (state->graymode==0) { memcpy(state->pu->imageData,buffer->data+w*h,w*h4); // read U memcpy(state->pv->imageData,buffer->data+w*h+w*h4,w*h4); // read v } vcos_semaphore_post(&state->capture_done_sem); vcos_semaphore_wait(&state->capture_sem); mmal_buffer_header_mem_unlock(buffer); } else { vcos_log_error("buffer null"); } } else { vcos_log_error("Received a encoder buffer callback with no state"); } // release buffer back to the pool mmal_buffer_header_release(buffer); // and send one back to the port (if still open) if (port->is_enabled) { MMAL_STATUS_T status; new_buffer = mmal_queue_get(state->video_pool->queue); if (new_buffer) status = mmal_port_send_buffer(port, new_buffer); if (!new_buffer || status != MMAL_SUCCESS) vcos_log_error("Unable to return a buffer to the encoder port"); } }
/** * main */ int main(int argc, const char **argv) { // Our main data storage vessel.. RASPIVID_STATE state; MMAL_STATUS_T status = MMAL_SUCCESS; MMAL_PORT_T *camera_preview_port = NULL; MMAL_PORT_T *camera_video_port = NULL; MMAL_PORT_T *camera_still_port = NULL; MMAL_PORT_T *preview_input_port = NULL; MMAL_PORT_T *encoder_input_port = NULL; MMAL_PORT_T *encoder_output_port = NULL; FILE *output_file = NULL; bcm_host_init(); // Register our application with the logging system vcos_log_register("RaspiVid", VCOS_LOG_CATEGORY); signal(SIGINT, signal_handler); default_status(&state); // Do we have any parameters if (argc == 1) { fprintf(stderr, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING); display_valid_parameters(basename(argv[0])); exit(0); } // Parse the command line and put options in to our status structure if (parse_cmdline(argc, argv, &state)) { status = -1; exit(0); } if (state.verbose) { fprintf(stderr, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING); dump_status(&state); } // OK, we have a nice set of parameters. Now set up our components // We have three components. Camera, Preview and encoder. if ((status = create_camera_component(&state)) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to create camera component", __func__); } else if ((status = raspipreview_create(&state.preview_parameters)) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to create preview component", __func__); destroy_camera_component(&state); } else if ((status = create_encoder_component(&state)) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to create encode component", __func__); raspipreview_destroy(&state.preview_parameters); destroy_camera_component(&state); } else { PORT_USERDATA callback_data; if (state.verbose) fprintf(stderr, "Starting component connection stage\n"); camera_preview_port = state.camera_component->output[MMAL_CAMERA_PREVIEW_PORT]; camera_video_port = state.camera_component->output[MMAL_CAMERA_VIDEO_PORT]; camera_still_port = state.camera_component->output[MMAL_CAMERA_CAPTURE_PORT]; preview_input_port = state.preview_parameters.preview_component->input[0]; encoder_input_port = state.encoder_component->input[0]; encoder_output_port = state.encoder_component->output[0]; if (state.preview_parameters.wantPreview ) { if (state.verbose) { fprintf(stderr, "Connecting camera preview port to preview input port\n"); fprintf(stderr, "Starting video preview\n"); } // Connect camera to preview status = connect_ports(camera_preview_port, preview_input_port, &state.preview_connection); } else { status = MMAL_SUCCESS; } if (status == MMAL_SUCCESS) { if (state.verbose) fprintf(stderr, "Connecting camera stills port to encoder input port\n"); // Now connect the camera to the encoder status = connect_ports(camera_video_port, encoder_input_port, &state.encoder_connection); if (status != MMAL_SUCCESS) { vcos_log_error("%s: Failed to connect camera video port to encoder input", __func__); goto error; } if (state.filename) { if (state.filename[0] == '-') { output_file = stdout; // Ensure we don't upset the output stream with diagnostics/info state.verbose = 0; } else { if (state.verbose) fprintf(stderr, "Opening output file \"%s\"\n", state.filename); output_file = fopen(state.filename, "wb"); } if (!output_file) { // Notify user, carry on but discarding encoded output buffers vcos_log_error("%s: Error opening output file: %s\nNo output file will be generated\n", __func__, state.filename); } } // Set up our userdata - this is passed though to the callback where we need the information. callback_data.file_handle = output_file; callback_data.image = Mat(Size(state.width, state.height), CV_8UC1); callback_data.pstate = &state; callback_data.abort = 0; encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&callback_data; if (state.verbose) fprintf(stderr, "Enabling encoder output port\n"); // Enable the encoder output port and tell it its callback function status = mmal_port_enable(encoder_output_port, encoder_buffer_callback); if (status != MMAL_SUCCESS) { vcos_log_error("Failed to setup encoder output"); goto error; } if (state.demoMode) { // Run for the user specific time.. int num_iterations = state.timeout / state.demoInterval; int i; if (state.verbose) fprintf(stderr, "Running in demo mode\n"); for (i=0;state.timeout == 0 || i<num_iterations;i++) { raspicamcontrol_cycle_test(state.camera_component); vcos_sleep(state.demoInterval); } } else { // Only encode stuff if we have a filename and it opened if (output_file) { int wait; if (state.verbose) fprintf(stderr, "Starting video capture\n"); if (mmal_port_parameter_set_boolean(camera_video_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) { goto error; } // Send all the buffers to the encoder output port { int num = mmal_queue_length(state.encoder_pool->queue); int q; for (q=0;q<num;q++) { MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state.encoder_pool->queue); if (!buffer) vcos_log_error("Unable to get a required buffer %d from pool queue", q); if (mmal_port_send_buffer(encoder_output_port, buffer)!= MMAL_SUCCESS) vcos_log_error("Unable to send a buffer to encoder output port (%d)", q); } } // Now wait until we need to stop. Whilst waiting we do need to check to see if we have aborted (for example // out of storage space) // Going to check every ABORT_INTERVAL milliseconds for (wait = 0; state.timeout == 0 || wait < state.timeout; wait+= ABORT_INTERVAL) { vcos_sleep(ABORT_INTERVAL); if (callback_data.abort) break; } if (state.verbose) fprintf(stderr, "Finished capture\n"); } else { if (state.timeout) vcos_sleep(state.timeout); else for (;;) vcos_sleep(ABORT_INTERVAL); } } } else { mmal_status_to_int(status); vcos_log_error("%s: Failed to connect camera to preview", __func__); } error: mmal_status_to_int(status); if (state.verbose) fprintf(stderr, "Closing down\n"); // Disable all our ports that are not handled by connections check_disable_port(camera_still_port); check_disable_port(encoder_output_port); if (state.preview_parameters.wantPreview ) mmal_connection_destroy(state.preview_connection); mmal_connection_destroy(state.encoder_connection); // Can now close our file. Note disabling ports may flush buffers which causes // problems if we have already closed the file! if (output_file && output_file != stdout) fclose(output_file); /* Disable components */ if (state.encoder_component) mmal_component_disable(state.encoder_component); if (state.preview_parameters.preview_component) mmal_component_disable(state.preview_parameters.preview_component); if (state.camera_component) mmal_component_disable(state.camera_component); destroy_encoder_component(&state); raspipreview_destroy(&state.preview_parameters); destroy_camera_component(&state); if (state.verbose) fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n"); } if (status != MMAL_SUCCESS) raspicamcontrol_check_configuration(128); return 0; }
/** * Create the encoder component, set up its ports * * @param state Pointer to state control struct * * @return MMAL_SUCCESS if all OK, something else otherwise * */ static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state) { MMAL_COMPONENT_T *encoder = 0; MMAL_PORT_T *encoder_input = NULL, *encoder_output = NULL; MMAL_STATUS_T status; MMAL_POOL_T *pool; status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER, &encoder); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to create video encoder component"); goto error; } if (!encoder->input_num || !encoder->output_num) { status = MMAL_ENOSYS; vcos_log_error("Video encoder doesn't have input/output ports"); goto error; } encoder_input = encoder->input[0]; encoder_output = encoder->output[0]; // We want same format on input and output mmal_format_copy(encoder_output->format, encoder_input->format); // Only supporting H264 at the moment encoder_output->format->encoding = MMAL_ENCODING_H264; encoder_output->format->bitrate = state->bitrate; encoder_output->buffer_size = encoder_output->buffer_size_recommended; if (encoder_output->buffer_size < encoder_output->buffer_size_min) encoder_output->buffer_size = encoder_output->buffer_size_min; encoder_output->buffer_num = encoder_output->buffer_num_recommended; if (encoder_output->buffer_num < encoder_output->buffer_num_min) encoder_output->buffer_num = encoder_output->buffer_num_min; // Commit the port changes to the output port status = mmal_port_format_commit(encoder_output); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to set format on video encoder output port"); goto error; } // Set the rate control parameter if (0) { MMAL_PARAMETER_VIDEO_RATECONTROL_T param = {{ MMAL_PARAMETER_RATECONTROL, sizeof(param)}, MMAL_VIDEO_RATECONTROL_DEFAULT}; status = mmal_port_parameter_set(encoder_output, ¶m.hdr); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to set ratecontrol"); goto error; } } if (state->intraperiod) { MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_INTRAPERIOD, sizeof(param)}, state->intraperiod}; status = mmal_port_parameter_set(encoder_output, ¶m.hdr); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to set intraperiod"); goto error; } } if (mmal_port_parameter_set_boolean(encoder_input, MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT, state->immutableInput) != MMAL_SUCCESS) { vcos_log_error("Unable to set immutable input flag"); // Continue rather than abort.. } // Enable component status = mmal_component_enable(encoder); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to enable video encoder component"); goto error; } /* Create pool of buffer headers for the output port to consume */ pool = mmal_port_pool_create(encoder_output, encoder_output->buffer_num, encoder_output->buffer_size); if (!pool) { vcos_log_error("Failed to create buffer header pool for encoder output port %s", encoder_output->name); } state->encoder_pool = pool; state->encoder_component = encoder; if (state->verbose) fprintf(stderr, "Encoder component done\n"); return status; error: if (encoder) mmal_component_destroy(encoder); return status; }
/** * Create the encoder component, set up its ports * * @param state Pointer to state control struct. encoder_component member set to the created camera_component if successfull. * * @return a MMAL_STATUS, MMAL_SUCCESS if all OK, something else otherwise */ static MMAL_STATUS_T create_encoder_component(RASPISTILL_STATE *state) { MMAL_COMPONENT_T *encoder = 0; MMAL_PORT_T *encoder_input = NULL, *encoder_output = NULL; MMAL_STATUS_T status; MMAL_POOL_T *pool; status = mmal_component_create(MMAL_COMPONENT_DEFAULT_IMAGE_ENCODER, &encoder); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to create JPEG encoder component"); goto error; } if (!encoder->input_num || !encoder->output_num) { status = MMAL_ENOSYS; vcos_log_error("JPEG encoder doesn't have input/output ports"); goto error; } encoder_input = encoder->input[0]; encoder_output = encoder->output[0]; // We want same format on input and output mmal_format_copy(encoder_output->format, encoder_input->format); // Specify out output format encoder_output->format->encoding = state->encoding; encoder_output->buffer_size = encoder_output->buffer_size_recommended; if (encoder_output->buffer_size < encoder_output->buffer_size_min) encoder_output->buffer_size = encoder_output->buffer_size_min; encoder_output->buffer_num = encoder_output->buffer_num_recommended; if (encoder_output->buffer_num < encoder_output->buffer_num_min) encoder_output->buffer_num = encoder_output->buffer_num_min; // Commit the port changes to the output port status = mmal_port_format_commit(encoder_output); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to set format on video encoder output port"); goto error; } // Set the JPEG quality level status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_JPEG_Q_FACTOR, state->quality); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to set JPEG quality"); goto error; } // Set up any required thumbnail { MMAL_PARAMETER_THUMBNAIL_CONFIG_T param_thumb = {{MMAL_PARAMETER_THUMBNAIL_CONFIGURATION, sizeof(MMAL_PARAMETER_THUMBNAIL_CONFIG_T)}, 0, 0, 0, 0}; if ( state->thumbnailConfig.width > 0 && state->thumbnailConfig.height > 0 ) { // Have a valid thumbnail defined param_thumb.enable = 1; param_thumb.width = state->thumbnailConfig.width; param_thumb.height = state->thumbnailConfig.height; param_thumb.quality = state->thumbnailConfig.quality; } status = mmal_port_parameter_set(encoder->control, ¶m_thumb.hdr); } // Enable component status = mmal_component_enable(encoder); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to enable video encoder component"); goto error; } /* Create pool of buffer headers for the output port to consume */ pool = mmal_port_pool_create(encoder_output, encoder_output->buffer_num, encoder_output->buffer_size); if (!pool) { vcos_log_error("Failed to create buffer header pool for encoder output port %s", encoder_output->name); } state->encoder_pool = pool; state->encoder_component = encoder; if (state->verbose) fprintf(stderr, "Encoder component done\n"); return status; error: if (encoder) mmal_component_destroy(encoder); return status; }
/** * buffer header callback function for camera output port * * Callback will dump buffer data to the specific file * * @param port Pointer to port from which callback originated * @param buffer mmal buffer header pointer */ static void camera_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) { int complete = 0; // We pass our file handle and other stuff in via the userdata field. PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata; if (pData) { int bytes_written = buffer->length; if (buffer->length && pData->file_handle) { mmal_buffer_header_mem_lock(buffer); bytes_written = fwrite(buffer->data, 1, buffer->length, pData->file_handle); mmal_buffer_header_mem_unlock(buffer); } // We need to check we wrote what we wanted - it's possible we have run out of storage. if (bytes_written != buffer->length) { vcos_log_error("Unable to write buffer to file - aborting"); complete = 1; } // Check end of frame or error if (buffer->flags & (MMAL_BUFFER_HEADER_FLAG_FRAME_END | MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED)) complete = 1; } else { vcos_log_error("Received a camera still buffer callback with no state"); } // release buffer back to the pool mmal_buffer_header_release(buffer); // and send one back to the port (if still open) if (port->is_enabled) { MMAL_STATUS_T status; MMAL_BUFFER_HEADER_T *new_buffer = mmal_queue_get(pData->pstate->camera_pool->queue); // and back to the port from there. if (new_buffer) { status = mmal_port_send_buffer(port, new_buffer); } if (!new_buffer || status != MMAL_SUCCESS) vcos_log_error("Unable to return the buffer to the camera still port"); } if (complete) { vcos_semaphore_post(&(pData->complete_semaphore)); } }
/** * main */ int main(int argc, const char **argv) { // Our main data storage vessel.. RASPISTILLYUV_STATE state; int exit_code = EX_OK; MMAL_STATUS_T status = MMAL_SUCCESS; MMAL_PORT_T *camera_preview_port = NULL; MMAL_PORT_T *camera_video_port = NULL; MMAL_PORT_T *camera_still_port = NULL; MMAL_PORT_T *preview_input_port = NULL; FILE *output_file = NULL; bcm_host_init(); // Register our application with the logging system vcos_log_register("RaspiStill", VCOS_LOG_CATEGORY); signal(SIGINT, signal_handler); // Disable USR1 for the moment - may be reenabled if go in to signal capture mode signal(SIGUSR1, SIG_IGN); default_status(&state); // Do we have any parameters if (argc == 1) { fprintf(stdout, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING); display_valid_parameters(basename(argv[0])); exit(EX_USAGE); } default_status(&state); // Parse the command line and put options in to our status structure if (parse_cmdline(argc, argv, &state)) { status = -1; exit(EX_USAGE); } if (state.verbose) { fprintf(stderr, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING); dump_status(&state); } // OK, we have a nice set of parameters. Now set up our components // We have two components. Camera and Preview // Camera is different in stills/video, but preview // is the same so handed off to a separate module if ((status = create_camera_component(&state)) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to create camera component", __func__); exit_code = EX_SOFTWARE; } else if ((status = raspipreview_create(&state.preview_parameters)) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to create preview component", __func__); destroy_camera_component(&state); exit_code = EX_SOFTWARE; } else { PORT_USERDATA callback_data; if (state.verbose) fprintf(stderr, "Starting component connection stage\n"); camera_preview_port = state.camera_component->output[MMAL_CAMERA_PREVIEW_PORT]; camera_video_port = state.camera_component->output[MMAL_CAMERA_VIDEO_PORT]; camera_still_port = state.camera_component->output[MMAL_CAMERA_CAPTURE_PORT]; // Note we are lucky that the preview and null sink components use the same input port // so we can simple do this without conditionals preview_input_port = state.preview_parameters.preview_component->input[0]; // Connect camera to preview (which might be a null_sink if no preview required) status = connect_ports(camera_preview_port, preview_input_port, &state.preview_connection); if (status == MMAL_SUCCESS) { VCOS_STATUS_T vcos_status; // Set up our userdata - this is passed though to the callback where we need the information. // Null until we open our filename callback_data.file_handle = NULL; callback_data.pstate = &state; vcos_status = vcos_semaphore_create(&callback_data.complete_semaphore, "RaspiStill-sem", 0); vcos_assert(vcos_status == VCOS_SUCCESS); camera_still_port->userdata = (struct MMAL_PORT_USERDATA_T *)&callback_data; if (state.verbose) fprintf(stderr, "Enabling camera still output port\n"); // Enable the camera still output port and tell it its callback function status = mmal_port_enable(camera_still_port, camera_buffer_callback); if (status != MMAL_SUCCESS) { vcos_log_error("Failed to setup camera output"); goto error; } if (state.verbose) fprintf(stderr, "Starting video preview\n"); int frame, keep_looping = 1; FILE *output_file = NULL; char *use_filename = NULL; // Temporary filename while image being written char *final_filename = NULL; // Name that file gets once writing complete frame = 0; while (keep_looping) { keep_looping = wait_for_next_frame(&state, &frame); // Open the file if (state.filename) { if (state.filename[0] == '-') { output_file = stdout; // Ensure we don't upset the output stream with diagnostics/info state.verbose = 0; } else { vcos_assert(use_filename == NULL && final_filename == NULL); status = create_filenames(&final_filename, &use_filename, state.filename, frame); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to create filenames"); goto error; } if (state.verbose) fprintf(stderr, "Opening output file %s\n", final_filename); // Technically it is opening the temp~ filename which will be ranamed to the final filename output_file = fopen(use_filename, "wb"); if (!output_file) { // Notify user, carry on but discarding encoded output buffers vcos_log_error("%s: Error opening output file: %s\nNo output file will be generated\n", __func__, use_filename); } } callback_data.file_handle = output_file; } if (output_file) { int num, q; // There is a possibility that shutter needs to be set each loop. if (mmal_status_to_int(mmal_port_parameter_set_uint32(state.camera_component->control, MMAL_PARAMETER_SHUTTER_SPEED, state.camera_parameters.shutter_speed) != MMAL_SUCCESS)) vcos_log_error("Unable to set shutter speed"); // Send all the buffers to the camera output port num = mmal_queue_length(state.camera_pool->queue); for (q=0;q<num;q++) { MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state.camera_pool->queue); if (!buffer) vcos_log_error("Unable to get a required buffer %d from pool queue", q); if (mmal_port_send_buffer(camera_still_port, buffer)!= MMAL_SUCCESS) vcos_log_error("Unable to send a buffer to camera output port (%d)", q); } if (state.burstCaptureMode && frame==1) { mmal_port_parameter_set_boolean(state.camera_component->control, MMAL_PARAMETER_CAMERA_BURST_CAPTURE, 1); } if (state.verbose) fprintf(stderr, "Starting capture %d\n", frame); if (mmal_port_parameter_set_boolean(camera_still_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to start capture", __func__); } else { // Wait for capture to complete // For some reason using vcos_semaphore_wait_timeout sometimes returns immediately with bad parameter error // even though it appears to be all correct, so reverting to untimed one until figure out why its erratic vcos_semaphore_wait(&callback_data.complete_semaphore); if (state.verbose) fprintf(stderr, "Finished capture %d\n", frame); } // Ensure we don't die if get callback with no open file callback_data.file_handle = NULL; if (output_file != stdout) { rename_file(&state, output_file, final_filename, use_filename, frame); } } if (use_filename) { free(use_filename); use_filename = NULL; } if (final_filename) { free(final_filename); final_filename = NULL; } } // end for (frame) vcos_semaphore_delete(&callback_data.complete_semaphore); } else { mmal_status_to_int(status); vcos_log_error("%s: Failed to connect camera to preview", __func__); } error: mmal_status_to_int(status); if (state.verbose) fprintf(stderr, "Closing down\n"); if (output_file) fclose(output_file); // Disable all our ports that are not handled by connections check_disable_port(camera_video_port); if (state.preview_connection) mmal_connection_destroy(state.preview_connection); /* Disable components */ if (state.preview_parameters.preview_component) mmal_component_disable(state.preview_parameters.preview_component); if (state.camera_component) mmal_component_disable(state.camera_component); raspipreview_destroy(&state.preview_parameters); destroy_camera_component(&state); if (state.verbose) fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n"); } if (status != MMAL_SUCCESS) raspicamcontrol_check_configuration(128); return exit_code; }
/** * Create the encoder component, set up its ports * * @param state Pointer to state control struct * * @return 0 if failed, pointer to component if successful * */ static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state) { MMAL_COMPONENT_T *encoder = 0; MMAL_PORT_T *encoder_input = NULL, *encoder_output = NULL; MMAL_STATUS_T status; MMAL_POOL_T *pool; //printf("point1\n"); status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER, &encoder); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to create video encoder component"); goto error; } if (!encoder->input_num || !encoder->output_num) { status = MMAL_ENOSYS; vcos_log_error("Video encoder doesn't have input/output ports"); goto error; } encoder_input = encoder->input[0]; encoder_output = encoder->output[0]; // We want same format on input and output mmal_format_copy(encoder_output->format, encoder_input->format); // Only supporting H264 at the moment encoder_output->format->encoding = MMAL_ENCODING_H264; encoder_output->format->bitrate = state->bitrate; encoder_output->buffer_size = encoder_output->buffer_size_recommended; if (encoder_output->buffer_size < encoder_output->buffer_size_min) encoder_output->buffer_size = encoder_output->buffer_size_min; encoder_output->buffer_num = encoder_output->buffer_num_recommended; if (encoder_output->buffer_num < encoder_output->buffer_num_min) encoder_output->buffer_num = encoder_output->buffer_num_min; // We need to set the frame rate on output to 0, to ensure it gets // updated correctly from the input framerate when port connected encoder_output->format->es->video.frame_rate.num = 0; encoder_output->format->es->video.frame_rate.den = 1; // Commit the port changes to the output port status = mmal_port_format_commit(encoder_output); //printf("point2\n"); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to set format on video encoder output port"); goto error; } // Set the rate control parameter if (0) { MMAL_PARAMETER_VIDEO_RATECONTROL_T param = {{ MMAL_PARAMETER_RATECONTROL, sizeof(param)}, MMAL_VIDEO_RATECONTROL_DEFAULT}; status = mmal_port_parameter_set(encoder_output, ¶m.hdr); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to set ratecontrol"); goto error; } } if (state->intraperiod) { MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_INTRAPERIOD, sizeof(param)}, state->intraperiod}; status = mmal_port_parameter_set(encoder_output, ¶m.hdr); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to set intraperiod"); goto error; } } if (state->quantisationParameter) { MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT, sizeof(param)}, state->quantisationParameter}; status = mmal_port_parameter_set(encoder_output, ¶m.hdr); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to set initial QP"); goto error; } MMAL_PARAMETER_UINT32_T param2 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT, sizeof(param)}, state->quantisationParameter}; status = mmal_port_parameter_set(encoder_output, ¶m2.hdr); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to set min QP"); goto error; } MMAL_PARAMETER_UINT32_T param3 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, sizeof(param)}, state->quantisationParameter}; status = mmal_port_parameter_set(encoder_output, ¶m3.hdr); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to set max QP"); goto error; } } { MMAL_PARAMETER_VIDEO_PROFILE_T param; param.hdr.id = MMAL_PARAMETER_PROFILE; param.hdr.size = sizeof(param); //param.profile[0].profile = state->profile; param.profile[0].profile = MMAL_VIDEO_PROFILE_H264_HIGH; param.profile[0].level = MMAL_VIDEO_LEVEL_H264_4; // This is the only value supported status = mmal_port_parameter_set(encoder_output, ¶m.hdr); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to set H264 profile"); goto error; } } if (mmal_port_parameter_set_boolean(encoder_input, MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT, state->immutableInput) != MMAL_SUCCESS) { vcos_log_error("Unable to set immutable input flag"); // Continue rather than abort.. } //set INLINE HEADER flag to generate SPS and PPS for every IDR if requested if (mmal_port_parameter_set_boolean(encoder_output, MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER, state->bInlineHeaders) != MMAL_SUCCESS) { vcos_log_error("failed to set INLINE HEADER FLAG parameters"); // Continue rather than abort.. } //set INLINE VECTORS flag to request motion vector estimates if (mmal_port_parameter_set_boolean(encoder_output, MMAL_PARAMETER_VIDEO_ENCODE_INLINE_VECTORS, state->inlineMotionVectors) != MMAL_SUCCESS) { vcos_log_error("failed to set INLINE VECTORS parameters"); // Continue rather than abort.. } // Enable component status = mmal_component_enable(encoder); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to enable video encoder component"); goto error; } /* Create pool of buffer headers for the output port to consume */ pool = mmal_port_pool_create(encoder_output, encoder_output->buffer_num, encoder_output->buffer_size); if (!pool) { vcos_log_error("Failed to create buffer header pool for encoder output port %s", encoder_output->name); goto error; } state->encoder_pool = pool; state->encoder_component = encoder; /*if (state->verbose) fprintf(stderr, "Encoder component done\n"); */ return status; error: if (encoder) mmal_component_destroy(encoder); state->encoder_component = NULL; return status; }
/** * Create the camera component, set up its ports * * @param state Pointer to state control struct * * @return 0 if failed, pointer to component if successful * */ static MMAL_STATUS_T create_camera_component(RASPISTILLYUV_STATE *state) { MMAL_COMPONENT_T *camera = 0; MMAL_ES_FORMAT_T *format; MMAL_PORT_T *preview_port = NULL, *video_port = NULL, *still_port = NULL; MMAL_STATUS_T status; MMAL_POOL_T *pool; /* Create the component */ status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera); if (status != MMAL_SUCCESS) { vcos_log_error("Failed to create camera component"); goto error; } MMAL_PARAMETER_INT32_T camera_num = {{MMAL_PARAMETER_CAMERA_NUM, sizeof(camera_num)}, state->cameraNum}; status = mmal_port_parameter_set(camera->control, &camera_num.hdr); if (status != MMAL_SUCCESS) { vcos_log_error("Could not select camera : error %d", status); goto error; } if (!camera->output_num) { status = MMAL_ENOSYS; vcos_log_error("Camera doesn't have output ports"); goto error; } preview_port = camera->output[MMAL_CAMERA_PREVIEW_PORT]; video_port = camera->output[MMAL_CAMERA_VIDEO_PORT]; still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT]; if (state->settings) { MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T change_event_request = {{MMAL_PARAMETER_CHANGE_EVENT_REQUEST, sizeof(MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T)}, MMAL_PARAMETER_CAMERA_SETTINGS, 1}; status = mmal_port_parameter_set(camera->control, &change_event_request.hdr); if ( status != MMAL_SUCCESS ) { vcos_log_error("No camera settings events"); } } // Enable the camera, and tell it its control callback function status = mmal_port_enable(camera->control, camera_control_callback); if (status != MMAL_SUCCESS ) { vcos_log_error("Unable to enable control port : error %d", status); goto error; } // set up the camera configuration { MMAL_PARAMETER_CAMERA_CONFIG_T cam_config = { { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) }, .max_stills_w = state->width, .max_stills_h = state->height, .stills_yuv422 = 0, .one_shot_stills = 1, .max_preview_video_w = state->preview_parameters.previewWindow.width, .max_preview_video_h = state->preview_parameters.previewWindow.height, .num_preview_video_frames = 3, .stills_capture_circular_buffer_height = 0, .fast_preview_resume = 0, .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RESET_STC }; if (state->fullResPreview) { cam_config.max_preview_video_w = state->width; cam_config.max_preview_video_h = state->height; } mmal_port_parameter_set(camera->control, &cam_config.hdr); } raspicamcontrol_set_all_parameters(camera, &state->camera_parameters); // Now set up the port formats format = preview_port->format; format->encoding = MMAL_ENCODING_OPAQUE; format->encoding_variant = MMAL_ENCODING_I420; if(state->camera_parameters.shutter_speed > 6000000) { MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)}, { 50, 1000 }, {166, 1000}}; mmal_port_parameter_set(preview_port, &fps_range.hdr); } else if(state->camera_parameters.shutter_speed > 1000000) { MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)}, { 166, 1000 }, {999, 1000}}; mmal_port_parameter_set(preview_port, &fps_range.hdr); } if (state->fullResPreview) { // In this mode we are forcing the preview to be generated from the full capture resolution. // This runs at a max of 15fps with the OV5647 sensor. format->es->video.width = VCOS_ALIGN_UP(state->width, 32); format->es->video.height = VCOS_ALIGN_UP(state->height, 16); format->es->video.crop.x = 0; format->es->video.crop.y = 0; format->es->video.crop.width = state->width; format->es->video.crop.height = state->height; format->es->video.frame_rate.num = FULL_RES_PREVIEW_FRAME_RATE_NUM; format->es->video.frame_rate.den = FULL_RES_PREVIEW_FRAME_RATE_DEN; } else { // Use a full FOV 4:3 mode format->es->video.width = VCOS_ALIGN_UP(state->preview_parameters.previewWindow.width, 32); format->es->video.height = VCOS_ALIGN_UP(state->preview_parameters.previewWindow.height, 16); format->es->video.crop.x = 0; format->es->video.crop.y = 0; format->es->video.crop.width = state->preview_parameters.previewWindow.width; format->es->video.crop.height = state->preview_parameters.previewWindow.height; format->es->video.frame_rate.num = PREVIEW_FRAME_RATE_NUM; format->es->video.frame_rate.den = PREVIEW_FRAME_RATE_DEN; } status = mmal_port_format_commit(preview_port); if (status != MMAL_SUCCESS ) { vcos_log_error("camera viewfinder format couldn't be set"); goto error; } // Set the same format on the video port (which we dont use here) mmal_format_full_copy(video_port->format, format); status = mmal_port_format_commit(video_port); if (status != MMAL_SUCCESS ) { vcos_log_error("camera video format couldn't be set"); goto error; } // Ensure there are enough buffers to avoid dropping frames if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM) video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM; format = still_port->format; if(state->camera_parameters.shutter_speed > 6000000) { MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)}, { 50, 1000 }, {166, 1000}}; mmal_port_parameter_set(still_port, &fps_range.hdr); } else if(state->camera_parameters.shutter_speed > 1000000) { MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)}, { 167, 1000 }, {999, 1000}}; mmal_port_parameter_set(still_port, &fps_range.hdr); } // Set our stills format on the stills port if (state->useRGB) { format->encoding = MMAL_ENCODING_BGR24; format->encoding_variant = MMAL_ENCODING_BGR24; } else { format->encoding = MMAL_ENCODING_I420; format->encoding_variant = MMAL_ENCODING_I420; } format->es->video.width = VCOS_ALIGN_UP(state->width, 32); format->es->video.height = VCOS_ALIGN_UP(state->height, 16); format->es->video.crop.x = 0; format->es->video.crop.y = 0; format->es->video.crop.width = state->width; format->es->video.crop.height = state->height; format->es->video.frame_rate.num = STILLS_FRAME_RATE_NUM; format->es->video.frame_rate.den = STILLS_FRAME_RATE_DEN; if (still_port->buffer_size < still_port->buffer_size_min) still_port->buffer_size = still_port->buffer_size_min; still_port->buffer_num = still_port->buffer_num_recommended; status = mmal_port_format_commit(still_port); if (status != MMAL_SUCCESS ) { vcos_log_error("camera still format couldn't be set"); goto error; } /* Enable component */ status = mmal_component_enable(camera); if (status != MMAL_SUCCESS ) { vcos_log_error("camera component couldn't be enabled"); goto error; } /* Create pool of buffer headers for the output port to consume */ pool = mmal_port_pool_create(still_port, still_port->buffer_num, still_port->buffer_size); if (!pool) { vcos_log_error("Failed to create buffer header pool for camera still port %s", still_port->name); } state->camera_pool = pool; state->camera_component = camera; if (state->verbose) fprintf(stderr, "Camera component done\n"); return status; error: if (camera) mmal_component_destroy(camera); return status; }
RaspiCamCvCapture * raspiCamCvCreateCameraCapture(int index) { RaspiCamCvCapture * capture = (RaspiCamCvCapture*)malloc(sizeof(RaspiCamCvCapture)); // Our main data storage vessel.. RASPIVID_STATE * state = (RASPIVID_STATE*)malloc(sizeof(RASPIVID_STATE)); capture->pState = state; MMAL_STATUS_T status = -1; MMAL_PORT_T *camera_video_port = NULL; MMAL_PORT_T *camera_video_port_2 = NULL; //MMAL_PORT_T *camera_still_port = NULL; MMAL_PORT_T *encoder_input_port = NULL; MMAL_PORT_T *encoder_output_port = NULL; bcm_host_init(); // read default status default_status(state); int w = state->width; int h = state->height; state->py = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 3); // Y component of YUV I420 frame if (state->graymode==0) { state->pu = cvCreateImage(cvSize(w/2,h/2), IPL_DEPTH_8U, 1); // U component of YUV I420 frame state->pv = cvCreateImage(cvSize(w/2,h/2), IPL_DEPTH_8U, 1); // V component of YUV I420 frame } vcos_semaphore_create(&state->capture_sem, "Capture-Sem", 0); vcos_semaphore_create(&state->capture_done_sem, "Capture-Done-Sem", 0); if (state->graymode==0) { state->pu_big = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1); state->pv_big = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 1); state->yuvImage = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 3); state->dstImage = cvCreateImage(cvSize(w,h), IPL_DEPTH_8U, 3); // final picture to display } //printf("point2.0\n"); // create camera if (!create_camera_component(state)) { vcos_log_error("%s: Failed to create camera component", __func__); raspiCamCvReleaseCapture(&capture); return NULL; } else if ((status = create_encoder_component(state)) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to create encode component", __func__); destroy_camera_component(state); return NULL; } //printf("point2.1\n"); //create_encoder_component(state); camera_video_port = state->camera_component->output[MMAL_CAMERA_VIDEO_PORT]; camera_video_port_2 = state->camera_component->output[MMAL_CAMERA_VIDEO_PORT_2]; //camera_still_port = state->camera_component->output[MMAL_CAMERA_CAPTURE_PORT]; encoder_input_port = state->encoder_component->input[0]; encoder_output_port = state->encoder_component->output[0]; // assign data to use for callback camera_video_port->userdata = (struct MMAL_PORT_USERDATA_T *)state; // assign data to use for callback camera_video_port_2->userdata = (struct MMAL_PORT_USERDATA_T *)state; // Now connect the camera to the encoder status = connect_ports(camera_video_port_2, encoder_input_port, &state->encoder_connection); if (state->filename) { if (state->filename[0] == '-') { state->callback_data.file_handle = stdout; } else { state->callback_data.file_handle = open_filename(state); } if (!state->callback_data.file_handle) { // Notify user, carry on but discarding encoded output buffers vcos_log_error("%s: Error opening output file: %s\nNo output file will be generated\n", __func__, state->filename); } } // Set up our userdata - this is passed though to the callback where we need the information. state->callback_data.pstate = state; state->callback_data.abort = 0; encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&state->callback_data; // Enable the encoder output port and tell it its callback function status = mmal_port_enable(encoder_output_port, encoder_buffer_callback); if (status != MMAL_SUCCESS) { state->encoder_connection = NULL; vcos_log_error("%s: Failed to connect camera video port to encoder input", __func__); return NULL; } if (status != MMAL_SUCCESS) { vcos_log_error("Failed to setup encoder output"); return NULL; } //mmal_port_enable(encoder_output_port, encoder_buffer_callback); // Only encode stuff if we have a filename and it opened // Note we use the copy in the callback, as the call back MIGHT change the file handle if (state->callback_data.file_handle) { int running = 1; // Send all the buffers to the encoder output port { int num = mmal_queue_length(state->encoder_pool->queue); int q; for (q=0;q<num;q++) { MMAL_BUFFER_HEADER_T *buffer2 = mmal_queue_get(state->encoder_pool->queue); if (!buffer2) vcos_log_error("Unable to get a required buffer %d from pool queue", q); if (mmal_port_send_buffer(encoder_output_port, buffer2)!= MMAL_SUCCESS) vcos_log_error("Unable to send a buffer to encoder output port (%d)", q); } } } // start capture if (mmal_port_parameter_set_boolean(camera_video_port_2, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) { vcos_log_error("%s: Failed to start capture", __func__); raspiCamCvReleaseCapture(&capture); return NULL; } // Send all the buffers to the video port int num = mmal_queue_length(state->video_pool->queue); int q; for (q = 0; q < num; q++) { MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state->video_pool->queue); if (!buffer) vcos_log_error("Unable to get a required buffer %d from pool queue", q); if (mmal_port_send_buffer(camera_video_port, buffer)!= MMAL_SUCCESS) vcos_log_error("Unable to send a buffer to encoder output port (%d)", q); } //mmal_status_to_int(status); // Disable all our ports that are not handled by connections //check_disable_port(camera_still_port); //if (status != 0) // raspicamcontrol_check_configuration(128); vcos_semaphore_wait(&state->capture_done_sem); return capture; }
/** * Function to wait in various ways (depending on settings) for the next frame * * @param state Pointer to the state data * @param [in][out] frame The last frame number, adjusted to next frame number on output * @return !0 if to continue, 0 if reached end of run */ static int wait_for_next_frame(RASPISTILLYUV_STATE *state, int *frame) { static int64_t complete_time = -1; int keep_running = 1; int64_t current_time = vcos_getmicrosecs64()/1000; if (complete_time == -1) complete_time = current_time + state->timeout; // if we have run out of time, flag we need to exit // If timeout = 0 then always continue if (current_time >= complete_time && state->timeout != 0) keep_running = 0; switch (state->frameNextMethod) { case FRAME_NEXT_SINGLE : // simple timeout for a single capture vcos_sleep(state->timeout); return 0; case FRAME_NEXT_FOREVER : { *frame+=1; // Have a sleep so we don't hog the CPU. vcos_sleep(10000); // Run forever so never indicate end of loop return 1; } case FRAME_NEXT_TIMELAPSE : { static int64_t next_frame_ms = -1; // Always need to increment by at least one, may add a skip later *frame += 1; if (next_frame_ms == -1) { vcos_sleep(state->timelapse); // Update our current time after the sleep current_time = vcos_getmicrosecs64()/1000; // Set our initial 'next frame time' next_frame_ms = current_time + state->timelapse; } else { int64_t this_delay_ms = next_frame_ms - current_time; if (this_delay_ms < 0) { // We are already past the next exposure time if (-this_delay_ms < -state->timelapse/2) { // Less than a half frame late, take a frame and hope to catch up next time next_frame_ms += state->timelapse; vcos_log_error("Frame %d is %d ms late", *frame, (int)(-this_delay_ms)); } else { int nskip = 1 + (-this_delay_ms)/state->timelapse; vcos_log_error("Skipping frame %d to restart at frame %d", *frame, *frame+nskip); *frame += nskip; this_delay_ms += nskip * state->timelapse; vcos_sleep(this_delay_ms); next_frame_ms += (nskip + 1) * state->timelapse; } } else { vcos_sleep(this_delay_ms); next_frame_ms += state->timelapse; } } return keep_running; } case FRAME_NEXT_KEYPRESS : { int ch; if (state->verbose) fprintf(stderr, "Press Enter to capture, X then ENTER to exit\n"); ch = getchar(); *frame+=1; if (ch == 'x' || ch == 'X') return 0; else { return keep_running; } } case FRAME_NEXT_IMMEDIATELY : { // Not waiting, just go to next frame. // Actually, we do need a slight delay here otherwise exposure goes // badly wrong since we never allow it frames to work it out // This could probably be tuned down. // First frame has a much longer delay to ensure we get exposure to a steady state if (*frame == 0) vcos_sleep(1000); else vcos_sleep(30); *frame+=1; return keep_running; } case FRAME_NEXT_GPIO : { // Intended for GPIO firing of a capture return 0; } case FRAME_NEXT_SIGNAL : { // Need to wait for a SIGUSR1 signal sigset_t waitset; int sig; int result = 0; sigemptyset( &waitset ); sigaddset( &waitset, SIGUSR1 ); // We are multi threaded because we use mmal, so need to use the pthread // variant of procmask to block SIGUSR1 so we can wait on it. pthread_sigmask( SIG_BLOCK, &waitset, NULL ); if (state->verbose) { fprintf(stderr, "Waiting for SIGUSR1 to initiate capture\n"); } result = sigwait( &waitset, &sig ); if (state->verbose) { if( result == 0) { fprintf(stderr, "Received SIGUSR1\n"); } else { fprintf(stderr, "Bad signal received - error %d\n", errno); } } *frame+=1; return keep_running; } } // end of switch // Should have returned by now, but default to timeout return keep_running; }
/** * Create the camera component, set up its ports * * @param state Pointer to state control struct * * @return MMAL_SUCCESS if all OK, something else otherwise * */ static MMAL_STATUS_T create_camera_component(RASPIVID_STATE *state) { MMAL_COMPONENT_T *camera = 0; MMAL_ES_FORMAT_T *format; MMAL_PORT_T *preview_port = NULL, *video_port = NULL, *still_port = NULL; MMAL_STATUS_T status; /* Create the component */ status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera); if (status != MMAL_SUCCESS) { vcos_log_error("Failed to create camera component"); goto error; } if (!camera->output_num) { status = MMAL_ENOSYS; vcos_log_error("Camera doesn't have output ports"); goto error; } preview_port = camera->output[MMAL_CAMERA_PREVIEW_PORT]; video_port = camera->output[MMAL_CAMERA_VIDEO_PORT]; still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT]; // Enable the camera, and tell it its control callback function status = mmal_port_enable(camera->control, camera_control_callback); if (status != MMAL_SUCCESS) { vcos_log_error("Unable to enable control port : error %d", status); goto error; } // set up the camera configuration { MMAL_PARAMETER_CAMERA_CONFIG_T cam_config = { { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) }, .max_stills_w = state->width, .max_stills_h = state->height, .stills_yuv422 = 0, .one_shot_stills = 0, .max_preview_video_w = state->width, .max_preview_video_h = state->height, .num_preview_video_frames = 3, .stills_capture_circular_buffer_height = 0, .fast_preview_resume = 0, .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RESET_STC }; mmal_port_parameter_set(camera->control, &cam_config.hdr); } // Now set up the port formats // Set the encode format on the Preview port // HW limitations mean we need the preview to be the same size as the required recorded output format = preview_port->format; format->encoding = MMAL_ENCODING_OPAQUE; format->encoding_variant = MMAL_ENCODING_I420; format->encoding = MMAL_ENCODING_OPAQUE; format->es->video.width = state->width; format->es->video.height = state->height; format->es->video.crop.x = 0; format->es->video.crop.y = 0; format->es->video.crop.width = state->width; format->es->video.crop.height = state->height; format->es->video.frame_rate.num = state->framerate; format->es->video.frame_rate.den = VIDEO_FRAME_RATE_DEN; status = mmal_port_format_commit(preview_port); if (status != MMAL_SUCCESS) { vcos_log_error("camera viewfinder format couldn't be set"); goto error; } // Set the encode format on the video port format = video_port->format; format->encoding_variant = MMAL_ENCODING_I420; format->encoding = MMAL_ENCODING_OPAQUE; format->es->video.width = state->width; format->es->video.height = state->height; format->es->video.crop.x = 0; format->es->video.crop.y = 0; format->es->video.crop.width = state->width; format->es->video.crop.height = state->height; format->es->video.frame_rate.num = state->framerate; format->es->video.frame_rate.den = VIDEO_FRAME_RATE_DEN; status = mmal_port_format_commit(video_port); if (status != MMAL_SUCCESS) { vcos_log_error("camera video format couldn't be set"); goto error; } // Ensure there are enough buffers to avoid dropping frames if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM) video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM; // Set the encode format on the still port format = still_port->format; format->encoding = MMAL_ENCODING_OPAQUE; format->encoding_variant = MMAL_ENCODING_I420; format->es->video.width = state->width; format->es->video.height = state->height; format->es->video.crop.x = 0; format->es->video.crop.y = 0; format->es->video.crop.width = state->width; format->es->video.crop.height = state->height; format->es->video.frame_rate.num = 1; format->es->video.frame_rate.den = 1; status = mmal_port_format_commit(still_port); if (status != MMAL_SUCCESS) { vcos_log_error("camera still format couldn't be set"); goto error; } /* Ensure there are enough buffers to avoid dropping frames */ if (still_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM) still_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM; /* Enable component */ status = mmal_component_enable(camera); if (status != MMAL_SUCCESS) { vcos_log_error("camera component couldn't be enabled"); goto error; } raspicamcontrol_set_all_parameters(camera, &state->camera_parameters); state->camera_component = camera; if (state->verbose) fprintf(stderr, "Camera component done\n"); return status; error: if (camera) mmal_component_destroy(camera); return status; }