bool CMMALRenderer::init_vout(MMAL_ES_FORMAT_T *format) { MMAL_STATUS_T status; CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); /* Create video renderer */ status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &m_vout); if(status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to create vout component (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } m_vout->control->userdata = (struct MMAL_PORT_USERDATA_T *)this; status = mmal_port_enable(m_vout->control, vout_control_port_cb); if(status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to enable vout control port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } m_vout_input = m_vout->input[0]; m_vout_input->userdata = (struct MMAL_PORT_USERDATA_T *)this; mmal_format_full_copy(m_vout_input->format, format); status = mmal_port_format_commit(m_vout_input); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to commit vout input format (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } m_vout_input->buffer_num = std::max(m_vout_input->buffer_num_recommended, (uint32_t)m_NumYV12Buffers); m_vout_input->buffer_size = m_vout_input->buffer_size_recommended; status = mmal_port_enable(m_vout_input, vout_input_port_cb_static); if(status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to vout enable input port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } status = mmal_component_enable(m_vout); if(status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to enable vout component (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } if (m_format == RENDER_FMT_YUV420P) { m_vout_input_pool = mmal_pool_create(m_vout_input->buffer_num, m_vout_input->buffer_size); if (!m_vout_input_pool) { CLog::Log(LOGERROR, "%s::%s Failed to create pool for decoder input port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } } return true; }
static int flush_decoder(decoder_t *dec) { decoder_sys_t *sys = dec->p_sys; MMAL_BUFFER_HEADER_T *buffer; MMAL_STATUS_T status; int ret = 0; msg_Dbg(dec, "Flushing decoder ports..."); mmal_port_disable(sys->output); mmal_port_disable(sys->input); mmal_port_flush(sys->output); mmal_port_flush(sys->input); /* Reload extradata if available */ if (dec->fmt_in.i_codec == VLC_CODEC_H264) { if (dec->fmt_in.i_extra > 0) { status = mmal_format_extradata_alloc(sys->input->format, dec->fmt_in.i_extra); if (status == MMAL_SUCCESS) { memcpy(sys->input->format->extradata, dec->fmt_in.p_extra, dec->fmt_in.i_extra); sys->input->format->extradata_size = dec->fmt_in.i_extra; } else { msg_Err(dec, "Failed to allocate extra format data on input port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); } } } status = mmal_port_format_commit(sys->input); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to commit format for input port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); } mmal_port_enable(sys->output, output_port_cb); mmal_port_enable(sys->input, input_port_cb); while (atomic_load(&sys->output_in_transit)) vlc_sem_wait(&sys->sem); /* Free pictures which are decoded but have not yet been sent * out to the core */ while ((buffer = mmal_queue_get(sys->decoded_pictures))) { picture_t *pic = (picture_t *)buffer->user_data; picture_Release(pic); if (sys->output_pool) { buffer->user_data = NULL; buffer->alloc_size = 0; buffer->data = NULL; mmal_buffer_header_release(buffer); } } msg_Dbg(dec, "Ports flushed, returning to normal operation"); return ret; }
int Private_Impl_Still::startCapture() { // If the parameters were changed and this function wasn't called, it will be called here // However if the parameters weren't changed, the function won't do anything - it will return right away commitParameters(); if ( encoder_output_port->is_enabled ) { cout << API_NAME << ": Could not enable encoder output port. Try waiting longer before attempting to take another picture.\n"; return -1; } if ( mmal_port_enable ( encoder_output_port, buffer_callback ) != MMAL_SUCCESS ) { cout << API_NAME << ": Could not enable encoder output port.\n"; return -1; } int num = mmal_queue_length ( encoder_pool->queue ); for ( int b = 0; b < num; b++ ) { MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get ( encoder_pool->queue ); if ( !buffer ) cout << API_NAME << ": Could not get buffer (#" << b << ") from pool queue.\n"; if ( mmal_port_send_buffer ( encoder_output_port, buffer ) != MMAL_SUCCESS ) cout << API_NAME << ": Could not send a buffer (#" << b << ") to encoder output port.\n"; } if ( mmal_port_parameter_set_boolean ( camera_still_port, MMAL_PARAMETER_CAPTURE, 1 ) != MMAL_SUCCESS ) { cout << API_NAME << ": Failed to start capture.\n"; return -1; } return 0; }
/* 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; }
/* This is a camera path endpoint callback setup for GPU encoder data | to the ARM. The callback should handle final disposition of encoder data. */ boolean out_port_callback(CameraObject *obj, int port_num, void callback()) { MMAL_PORT_T *port; MMAL_STATUS_T status; char *msg = "mmal_port_enable"; int i, n; if (!obj->component) return FALSE; port = obj->component->output[port_num]; /* Create an initial queue of buffers for the output port. | FIXME? Can't handle callbacks for more than one splitter port | because I only have one pool_out per component. */ if (!obj->pool_out) { if ((obj->pool_out = mmal_port_pool_create(port, port->buffer_num, port->buffer_size)) == NULL) { log_printf("out_port_callback %s: mmal_port_pool_create failed.\n", obj->name); return FALSE; } } /* Connect the callback and initialize buffer pool of data that will | be sent to the callback. */ if ((status = mmal_port_enable(port, callback)) == MMAL_SUCCESS) { obj->port_out = port; port->userdata = (struct MMAL_PORT_USERDATA_T *) obj; /* Send all buffers in the created queue to the GPU output port. | These buffers will then be delivered back to the ARM with filled | GPU data via the above callback where we can process the data | and then resend the buffer back to the port to be refilled. */ msg = "mmal_port_send_buffer"; n = mmal_queue_length(obj->pool_out->queue); for (i = 0; i < n; ++i) { status = mmal_port_send_buffer(port, mmal_queue_get(obj->pool_out->queue)); if (status != MMAL_SUCCESS) break; } } if (status != MMAL_SUCCESS) { log_printf("out_port_callback %s: %s failed. Status %s\n", obj->name, msg, mmal_status[status]); return FALSE; } return TRUE; }
void ofxRaspicam::setup() { MMAL_STATUS_T status = MMAL_SUCCESS; bcm_host_init(); create_camera_component(); create_encoder_component(); camera_still_port = photo.camera->output[MMAL_CAMERA_CAPTURE_PORT]; encoder_input_port = photo.encoder_component->input[0]; encoder_output_port = photo.encoder_component->output[0]; VCOS_STATUS_T vcos_status; ofLogVerbose() << "Connecting camera stills port to encoder input port"; // Now connect the camera to the encoder status = connect_ports(camera_still_port, encoder_input_port, &photo.encoder_connection); if (status != MMAL_SUCCESS) { ofLogVerbose() << "connect camera video port to encoder input FAIL"; }else { ofLogVerbose() << "connect camera video port to encoder input PASS"; } // 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.photo = &photo; vcos_status = vcos_semaphore_create(&callback_data.complete_semaphore, "RaspiStill-sem", 0); vcos_assert(vcos_status == VCOS_SUCCESS); encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&callback_data; ofLogVerbose() << "Enabling encoder output port"; // 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) { ofLogVerbose() << "Setup encoder output FAIL, error: " << status; }else { ofLogVerbose() << "Setup encoder output PASS"; } }
void CMMALVideo::Reset(void) { if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); if (m_dec_input && m_dec_input->is_enabled) mmal_port_disable(m_dec_input); if (m_deint_connection && m_deint_connection->is_enabled) mmal_connection_disable(m_deint_connection); if (m_dec_output && m_dec_output->is_enabled) mmal_port_disable(m_dec_output); if (!m_finished) { if (m_dec_input) mmal_port_enable(m_dec_input, dec_input_port_cb); if (m_deint_connection) mmal_connection_enable(m_deint_connection); if (m_dec_output) mmal_port_enable(m_dec_output, dec_output_port_cb_static); } // blow all ready video frames bool old_drop_state = m_drop_state; SetDropState(true); pthread_mutex_lock(&m_output_mutex); while(!m_dts_queue.empty()) m_dts_queue.pop(); while (!m_demux_queue.empty()) m_demux_queue.pop(); m_demux_queue_length = 0; pthread_mutex_unlock(&m_output_mutex); if (!old_drop_state) SetDropState(false); if (!m_finished) SendCodecConfigData(); m_startframe = false; m_decoderPts = DVD_NOPTS_VALUE; m_droppedPics = 0; m_decode_frame_number = 1; m_preroll = !m_hints.stills && (m_speed == DVD_PLAYSPEED_NORMAL || m_speed == DVD_PLAYSPEED_PAUSE); }
static void ffmmal_flush(AVCodecContext *avctx) { MMALDecodeContext *ctx = avctx->priv_data; MMAL_COMPONENT_T *decoder = ctx->decoder; MMAL_STATUS_T status; ffmmal_stop_decoder(avctx); if ((status = mmal_port_enable(decoder->control, control_port_cb))) goto fail; if ((status = mmal_port_enable(decoder->input[0], input_callback))) goto fail; if ((status = mmal_port_enable(decoder->output[0], output_callback))) goto fail; return; fail: av_log(avctx, AV_LOG_ERROR, "MMAL flush error: %i\n", (int)status); }
bool CMMALVideo::DestroyDeinterlace() { MMAL_STATUS_T status; if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); assert(m_deint); assert(m_dec_output == m_deint->output[0]); status = mmal_port_disable(m_dec_output); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to disable decoder output port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } status = mmal_connection_destroy(m_deint_connection); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to destroy deinterlace connection (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } m_deint_connection = NULL; status = mmal_component_disable(m_deint); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to disable deinterlace component (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } status = mmal_component_destroy(m_deint); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to destroy deinterlace component (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } m_deint = NULL; m_dec->output[0]->buffer_size = m_dec->output[0]->buffer_size_min; m_dec->output[0]->buffer_num = m_dec->output[0]->buffer_num_recommended; m_dec->output[0]->userdata = (struct MMAL_PORT_USERDATA_T *)this; status = mmal_port_enable(m_dec->output[0], dec_output_port_cb_static); if (status != MMAL_SUCCESS) { CLog::Log(LOGERROR, "%s::%s Failed to enable decoder output port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); return false; } m_dec_output = m_dec->output[0]; m_interlace_method = VS_INTERLACEMETHOD_NONE; return true; }
MMAL_POOL_T* CCameraOutput::EnablePortCallbackAndCreateBufferPool(MMAL_PORT_T* port, MMAL_PORT_BH_CB_T cb, int buffer_count) { MMAL_STATUS_T status; MMAL_POOL_T* buffer_pool = 0; //setup video port buffer and a pool to hold them port->buffer_num = buffer_count; port->buffer_size = port->buffer_size_recommended; printf("Creating pool with %d buffers of size %d\n", port->buffer_num, port->buffer_size); buffer_pool = mmal_port_pool_create(port, port->buffer_num, port->buffer_size); if (!buffer_pool) { printf("Couldn't create video buffer pool\n"); goto error; } //enable the port and hand it the callback port->userdata = (struct MMAL_PORT_USERDATA_T *)this; status = mmal_port_enable(port, cb); if (status != MMAL_SUCCESS) { printf("Failed to set video buffer callback\n"); goto error; } //send all the buffers in our pool to the video port ready for use { int num = mmal_queue_length(buffer_pool->queue); int q; for (q=0;q<num;q++) { MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(buffer_pool->queue); if (!buffer) { printf("Unable to get a required buffer %d from pool queue\n", q); goto error; } else if (mmal_port_send_buffer(port, buffer)!= MMAL_SUCCESS) { printf("Unable to send a buffer to port (%d)\n", q); goto error; } } } return buffer_pool; error: if(buffer_pool) mmal_port_pool_destroy(port,buffer_pool); return NULL; }
void MmalVideoCamera::createBufferPool() { if (m_videoPort == NULL) { throw Exception("Target port is not set."); } // Create pool of buffer headers for the output port to consume m_videoPort->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM; m_videoPort->buffer_size = m_videoPort->buffer_size_recommended; m_pool = mmal_port_pool_create(m_videoPort, MAX(m_videoPort->buffer_num, NUM_IMAGE_BUFFERS), m_videoPort->buffer_size); if (m_pool == NULL) { throw Exception("Failed to create buffer header pool for encoder output port"); } // Set the userdata m_callbackData->pool = m_pool; m_callbackData->acquire = false; m_videoPort->userdata = (struct MMAL_PORT_USERDATA_T *) m_callbackData; // Enable the encoder output port and tell it its callback function if (mmal_port_enable(m_videoPort, EncoderBufferCallback) != MMAL_SUCCESS) { throw Exception("Error enabling the encoder buffer callback"); } else { m_videoPortEnabled = true; } // Send all the buffers to the encoder output port sendBuffers(); // Start the capture if (mmal_port_parameter_set_boolean(m_videoPort, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) { throw Exception("Error starting the camera capture"); } }
/** * 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; }
int main(int argc, char **argv) { MMAL_COMPONENT_T *camera =0; MMAL_COMPONENT_T *preview=0; MMAL_COMPONENT_T *encoder=0; MMAL_CONNECTION_T *preview_conn=0; MMAL_CONNECTION_T *encoder_conn=0; USERDATA_T callback_data; // bcm should be initialized before any GPU call is made bcm_host_init(); setNonDefaultOptions(argc, argv); // Open file to save the video open_new_file_handle(&callback_data, output_file_name); fprintf(stderr, "Output Filename: %s\n", output_file_name); // Create Camera, set default values and enable it vcos_assert((mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera) == MMAL_SUCCESS) && "Failed creating camera component"); vcos_assert((set_camera_component_defaults(camera)) == MMAL_SUCCESS && "Failed setting camera components default values"); vcos_assert((mmal_component_enable(camera) == MMAL_SUCCESS) && "Failed to enable camera component"); // Create Preview, set default values and enable it vcos_assert((mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &preview) == MMAL_SUCCESS) && "Failed creating preview component"); vcos_assert((set_preview_component_defaults(preview) == MMAL_SUCCESS) && "Failed setting preview components default values"); vcos_assert((mmal_component_enable(preview) == MMAL_SUCCESS) && "Failed to enable camera component"); // Create Encoder, set defaults, enable it and create encoder pool vcos_assert((mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER, &encoder) == MMAL_SUCCESS) && "Failed to create encoder component"); vcos_assert((encoder->input_num && encoder->output_num) && "Video encoder does not have input/output ports\n"); set_encoder_component_defaults(encoder); vcos_assert((mmal_component_enable(encoder) == MMAL_SUCCESS) && "Failed enabling encoder component"); callback_data.pool = (MMAL_POOL_T *)mmal_port_pool_create(encoder->output[0], encoder->output[0]->buffer_num, encoder->output[0]->buffer_size); vcos_assert(callback_data.pool && "Failed creating encoder pool\n"); // Setup connections vcos_assert((mmal_connection_create(&preview_conn, camera->output[0], preview->input[0], MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT) == MMAL_SUCCESS) && "Failed stablishing connection between camera output 0 and preview"); vcos_assert((mmal_connection_enable(preview_conn) == MMAL_SUCCESS) && "Failed enabling connection between camera output 0 and preview"); vcos_assert((mmal_connection_create(&encoder_conn, camera->output[1], encoder->input[0], // MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT) == MMAL_SUCCESS) MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT) == MMAL_SUCCESS) && "Failed creating encoder connection to capture (camera output 1)"); vcos_assert((mmal_connection_enable(encoder_conn) == MMAL_SUCCESS) && "Failed enabling encoder connection to capture (campera output 1)"); encoder_conn->callback = connection_video2encoder_callback; // Set callback and enable encoder port encoder->output[0]->userdata = (struct MMAL_PORT_USERDATA_T *)&callback_data; vcos_assert(MMAL_SUCCESS == mmal_port_enable(encoder->output[0], encoder_callback)); // Send the buffer to encode output port MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(callback_data.pool->queue); vcos_assert((mmal_port_send_buffer(encoder->output[0], buffer)== MMAL_SUCCESS) && "Unable to send buffer to encoder output port"); vcos_assert((mmal_port_parameter_set_boolean(camera->output[1], MMAL_PARAMETER_CAPTURE, 1) == MMAL_SUCCESS) && "Unable to set camera->output[1] capture parameter"); consume_queue_on_connection(encoder_conn->out, encoder_conn->pool->queue); while(1) { vcos_sleep(1000); // wait for exit call if (exit_prog){ vcos_sleep(500); // exit called, wait for all buffers be flushed break; } } return 0; }
static int change_output_format(decoder_t *dec) { MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T interlace_type; decoder_sys_t *sys = dec->p_sys; MMAL_STATUS_T status; int pool_size; int ret = 0; if (atomic_load(&sys->started)) { mmal_format_full_copy(sys->output->format, sys->output_format); status = mmal_port_format_commit(sys->output); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to commit output format (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); ret = -1; goto port_reset; } goto apply_fmt; } port_reset: msg_Dbg(dec, "%s: Do full port reset", __func__); status = mmal_port_disable(sys->output); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to disable output port (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); ret = -1; goto out; } mmal_format_full_copy(sys->output->format, sys->output_format); status = mmal_port_format_commit(sys->output); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to commit output format (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); ret = -1; goto out; } if (sys->opaque) { sys->output->buffer_num = NUM_ACTUAL_OPAQUE_BUFFERS; pool_size = NUM_DECODER_BUFFER_HEADERS; } else { sys->output->buffer_num = __MAX(sys->output->buffer_num_recommended, MIN_NUM_BUFFERS_IN_TRANSIT); pool_size = sys->output->buffer_num; } sys->output->buffer_size = sys->output->buffer_size_recommended; status = mmal_port_enable(sys->output, output_port_cb); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to enable output port (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); ret = -1; goto out; } if (!atomic_load(&sys->started)) { if (!sys->opaque) { sys->output_pool = mmal_port_pool_create(sys->output, pool_size, 0); msg_Dbg(dec, "Created output pool with %d pictures", sys->output_pool->headers_num); } atomic_store(&sys->started, true); /* we need one picture from vout for each buffer header on the output * port */ dec->i_extra_picture_buffers = pool_size; /* remove what VLC core reserves as it is part of the pool_size * already */ if (dec->fmt_in.i_codec == VLC_CODEC_H264) dec->i_extra_picture_buffers -= 19; else dec->i_extra_picture_buffers -= 3; msg_Dbg(dec, "Request %d extra pictures", dec->i_extra_picture_buffers); } apply_fmt: dec->fmt_out.video.i_width = sys->output->format->es->video.width; dec->fmt_out.video.i_height = sys->output->format->es->video.height; dec->fmt_out.video.i_x_offset = sys->output->format->es->video.crop.x; dec->fmt_out.video.i_y_offset = sys->output->format->es->video.crop.y; dec->fmt_out.video.i_visible_width = sys->output->format->es->video.crop.width; dec->fmt_out.video.i_visible_height = sys->output->format->es->video.crop.height; dec->fmt_out.video.i_sar_num = sys->output->format->es->video.par.num; dec->fmt_out.video.i_sar_den = sys->output->format->es->video.par.den; dec->fmt_out.video.i_frame_rate = sys->output->format->es->video.frame_rate.num; dec->fmt_out.video.i_frame_rate_base = sys->output->format->es->video.frame_rate.den; /* Query interlaced type */ interlace_type.hdr.id = MMAL_PARAMETER_VIDEO_INTERLACE_TYPE; interlace_type.hdr.size = sizeof(MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T); status = mmal_port_parameter_get(sys->output, &interlace_type.hdr); if (status != MMAL_SUCCESS) { msg_Warn(dec, "Failed to query interlace type from decoder output port (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); } else { sys->b_progressive = (interlace_type.eMode == MMAL_InterlaceProgressive); sys->b_top_field_first = sys->b_progressive ? true : (interlace_type.eMode == MMAL_InterlaceFieldsInterleavedUpperFirst); msg_Dbg(dec, "Detected %s%s video (%d)", sys->b_progressive ? "progressive" : "interlaced", sys->b_progressive ? "" : (sys->b_top_field_first ? " tff" : " bff"), interlace_type.eMode); } out: mmal_format_free(sys->output_format); sys->output_format = NULL; return ret; }
static int OpenDecoder(decoder_t *dec) { int ret = VLC_SUCCESS; decoder_sys_t *sys; MMAL_PARAMETER_UINT32_T extra_buffers; MMAL_STATUS_T status; if (dec->fmt_in.i_cat != VIDEO_ES) return VLC_EGENERIC; if (dec->fmt_in.i_codec != VLC_CODEC_MPGV && dec->fmt_in.i_codec != VLC_CODEC_H264) return VLC_EGENERIC; sys = calloc(1, sizeof(decoder_sys_t)); if (!sys) { ret = VLC_ENOMEM; goto out; } dec->p_sys = sys; dec->b_need_packetized = true; sys->opaque = var_InheritBool(dec, MMAL_OPAQUE_NAME); bcm_host_init(); status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &sys->component); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to create MMAL component %s (status=%"PRIx32" %s)", MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->component->control->userdata = (struct MMAL_PORT_USERDATA_T *)dec; status = mmal_port_enable(sys->component->control, control_port_cb); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to enable control port %s (status=%"PRIx32" %s)", sys->component->control->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->input = sys->component->input[0]; sys->input->userdata = (struct MMAL_PORT_USERDATA_T *)dec; if (dec->fmt_in.i_codec == VLC_CODEC_MPGV) sys->input->format->encoding = MMAL_ENCODING_MP2V; else sys->input->format->encoding = MMAL_ENCODING_H264; if (dec->fmt_in.i_codec == VLC_CODEC_H264) { if (dec->fmt_in.i_extra > 0) { status = mmal_format_extradata_alloc(sys->input->format, dec->fmt_in.i_extra); if (status == MMAL_SUCCESS) { memcpy(sys->input->format->extradata, dec->fmt_in.p_extra, dec->fmt_in.i_extra); sys->input->format->extradata_size = dec->fmt_in.i_extra; } else { msg_Err(dec, "Failed to allocate extra format data on input port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); } } } status = mmal_port_format_commit(sys->input); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to commit format for input port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->input->buffer_size = sys->input->buffer_size_recommended; sys->input->buffer_num = sys->input->buffer_num_recommended; status = mmal_port_enable(sys->input, input_port_cb); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to enable input port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->output = sys->component->output[0]; sys->output->userdata = (struct MMAL_PORT_USERDATA_T *)dec; if (sys->opaque) { extra_buffers.hdr.id = MMAL_PARAMETER_EXTRA_BUFFERS; extra_buffers.hdr.size = sizeof(MMAL_PARAMETER_UINT32_T); extra_buffers.value = NUM_EXTRA_BUFFERS; status = mmal_port_parameter_set(sys->output, &extra_buffers.hdr); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to set MMAL_PARAMETER_EXTRA_BUFFERS on output port (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } msg_Dbg(dec, "Activate zero-copy for output port"); MMAL_PARAMETER_BOOLEAN_T zero_copy = { { MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T) }, 1 }; status = mmal_port_parameter_set(sys->output, &zero_copy.hdr); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to set zero copy on port %s (status=%"PRIx32" %s)", sys->output->name, status, mmal_status_to_string(status)); goto out; } } status = mmal_port_enable(sys->output, output_port_cb); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to enable output port %s (status=%"PRIx32" %s)", sys->output->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } status = mmal_component_enable(sys->component); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to enable component %s (status=%"PRIx32" %s)", sys->component->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->input_pool = mmal_pool_create(sys->input->buffer_num, 0); sys->decoded_pictures = mmal_queue_create(); if (sys->opaque) { dec->fmt_out.i_codec = VLC_CODEC_MMAL_OPAQUE; dec->fmt_out.video.i_chroma = VLC_CODEC_MMAL_OPAQUE; } else { dec->fmt_out.i_codec = VLC_CODEC_I420; dec->fmt_out.video.i_chroma = VLC_CODEC_I420; } dec->fmt_out.i_cat = VIDEO_ES; dec->pf_decode_video = decode; vlc_mutex_init_recursive(&sys->mutex); vlc_sem_init(&sys->sem, 0); out: if (ret != VLC_SUCCESS) CloseDecoder(dec); return ret; }
int main(int argc, char **argv) { MMAL_STATUS_T status = MMAL_EINVAL; MMAL_COMPONENT_T *decoder = 0; MMAL_POOL_T *pool_in = 0, *pool_out = 0; unsigned int count; if (argc < 2) { fprintf(stderr, "invalid arguments\n"); return -1; } #ifndef WIN32 // TODO verify that we dont really need to call bcm_host_init bcm_host_init(); #endif vcos_semaphore_create(&context.semaphore, "example", 1); SOURCE_OPEN(argv[1]); /* Create the decoder component. * This specific component exposes 2 ports (1 input and 1 output). Like most components * its expects the format of its input port to be set by the client in order for it to * know what kind of data it will be fed. */ status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &decoder); CHECK_STATUS(status, "failed to create decoder"); /* Set format of video decoder input port */ MMAL_ES_FORMAT_T *format_in = decoder->input[0]->format; format_in->type = MMAL_ES_TYPE_VIDEO; format_in->encoding = MMAL_ENCODING_H264; format_in->es->video.width = 1280; format_in->es->video.height = 720; format_in->es->video.frame_rate.num = 30; format_in->es->video.frame_rate.den = 1; format_in->es->video.par.num = 1; format_in->es->video.par.den = 1; /* If the data is known to be framed then the following flag should be set: * format_in->flags |= MMAL_ES_FORMAT_FLAG_FRAMED; */ SOURCE_READ_CODEC_CONFIG_DATA(codec_header_bytes, codec_header_bytes_size); status = mmal_format_extradata_alloc(format_in, codec_header_bytes_size); CHECK_STATUS(status, "failed to allocate extradata"); format_in->extradata_size = codec_header_bytes_size; if (format_in->extradata_size) memcpy(format_in->extradata, codec_header_bytes, format_in->extradata_size); status = mmal_port_format_commit(decoder->input[0]); CHECK_STATUS(status, "failed to commit format"); /* Display the output port format */ MMAL_ES_FORMAT_T *format_out = decoder->output[0]->format; fprintf(stderr, "%s\n", decoder->output[0]->name); fprintf(stderr, " type: %i, fourcc: %4.4s\n", format_out->type, (char *)&format_out->encoding); fprintf(stderr, " bitrate: %i, framed: %i\n", format_out->bitrate, !!(format_out->flags & MMAL_ES_FORMAT_FLAG_FRAMED)); fprintf(stderr, " extra data: %i, %p\n", format_out->extradata_size, format_out->extradata); fprintf(stderr, " width: %i, height: %i, (%i,%i,%i,%i)\n", format_out->es->video.width, format_out->es->video.height, format_out->es->video.crop.x, format_out->es->video.crop.y, format_out->es->video.crop.width, format_out->es->video.crop.height); /* The format of both ports is now set so we can get their buffer requirements and create * our buffer headers. We use the buffer pool API to create these. */ decoder->input[0]->buffer_num = decoder->input[0]->buffer_num_min; decoder->input[0]->buffer_size = decoder->input[0]->buffer_size_min; decoder->output[0]->buffer_num = decoder->output[0]->buffer_num_min; decoder->output[0]->buffer_size = decoder->output[0]->buffer_size_min; pool_in = mmal_pool_create(decoder->input[0]->buffer_num, decoder->input[0]->buffer_size); pool_out = mmal_pool_create(decoder->output[0]->buffer_num, decoder->output[0]->buffer_size); /* Create a queue to store our decoded video frames. The callback we will get when * a frame has been decoded will put the frame into this queue. */ context.queue = mmal_queue_create(); /* Store a reference to our context in each port (will be used during callbacks) */ decoder->input[0]->userdata = (void *)&context; decoder->output[0]->userdata = (void *)&context; /* Enable all the input port and the output port. * The callback specified here is the function which will be called when the buffer header * we sent to the component has been processed. */ status = mmal_port_enable(decoder->input[0], input_callback); CHECK_STATUS(status, "failed to enable input port"); status = mmal_port_enable(decoder->output[0], output_callback); CHECK_STATUS(status, "failed to enable output port"); /* Component won't start processing data until it is enabled. */ status = mmal_component_enable(decoder); CHECK_STATUS(status, "failed to enable component"); /* Start decoding */ fprintf(stderr, "start decoding\n"); /* This is the main processing loop */ for (count = 0; count < 500; count++) { MMAL_BUFFER_HEADER_T *buffer; /* Wait for buffer headers to be available on either of the decoder ports */ vcos_semaphore_wait(&context.semaphore); /* Send data to decode to the input port of the video decoder */ if ((buffer = mmal_queue_get(pool_in->queue)) != NULL) { SOURCE_READ_DATA_INTO_BUFFER(buffer); if (!buffer->length) break; fprintf(stderr, "sending %i bytes\n", (int)buffer->length); status = mmal_port_send_buffer(decoder->input[0], buffer); CHECK_STATUS(status, "failed to send buffer"); } /* Get our decoded frames */ while ((buffer = mmal_queue_get(context.queue)) != NULL) { /* We have a frame, do something with it (why not display it for instance?). * Once we're done with it, we release it. It will automatically go back * to its original pool so it can be reused for a new video frame. */ fprintf(stderr, "decoded frame\n"); mmal_buffer_header_release(buffer); } /* Send empty buffers to the output port of the decoder */ while ((buffer = mmal_queue_get(pool_out->queue)) != NULL) { status = mmal_port_send_buffer(decoder->output[0], buffer); CHECK_STATUS(status, "failed to send buffer"); } } /* Stop decoding */ fprintf(stderr, "stop decoding\n"); /* Stop everything. Not strictly necessary since mmal_component_destroy() * will do that anyway */ mmal_port_disable(decoder->input[0]); mmal_port_disable(decoder->output[0]); mmal_component_disable(decoder); error: /* Cleanup everything */ if (decoder) mmal_component_destroy(decoder); if (pool_in) mmal_pool_destroy(pool_in); if (pool_out) mmal_pool_destroy(pool_out); if (context.queue) mmal_queue_destroy(context.queue); SOURCE_CLOSE(); vcos_semaphore_delete(&context.semaphore); return status == MMAL_SUCCESS ? 0 : -1; }
/** * 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; }
static int Open(filter_t *filter) { int32_t frame_duration = filter->fmt_in.video.i_frame_rate != 0 ? (int64_t)1000000 * filter->fmt_in.video.i_frame_rate_base / filter->fmt_in.video.i_frame_rate : 0; MMAL_PARAMETER_IMAGEFX_PARAMETERS_T imfx_param = { { MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, sizeof(imfx_param) }, MMAL_PARAM_IMAGEFX_DEINTERLACE_ADV, 2, { 3, frame_duration } }; int ret = VLC_SUCCESS; MMAL_STATUS_T status; filter_sys_t *sys; msg_Dbg(filter, "Try to open mmal_deinterlace filter. frame_duration: %d!", frame_duration); if (filter->fmt_in.video.i_chroma != VLC_CODEC_MMAL_OPAQUE) return VLC_EGENERIC; if (filter->fmt_out.video.i_chroma != VLC_CODEC_MMAL_OPAQUE) return VLC_EGENERIC; sys = calloc(1, sizeof(filter_sys_t)); if (!sys) return VLC_ENOMEM; filter->p_sys = sys; bcm_host_init(); status = mmal_component_create(MMAL_COMPONENT_DEFAULT_DEINTERLACE, &sys->component); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to create MMAL component %s (status=%"PRIx32" %s)", MMAL_COMPONENT_DEFAULT_DEINTERLACE, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } status = mmal_port_parameter_set(sys->component->output[0], &imfx_param.hdr); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to configure MMAL component %s (status=%"PRIx32" %s)", MMAL_COMPONENT_DEFAULT_DEINTERLACE, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->component->control->userdata = (struct MMAL_PORT_USERDATA_T *)filter; status = mmal_port_enable(sys->component->control, control_port_cb); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to enable control port %s (status=%"PRIx32" %s)", sys->component->control->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->input = sys->component->input[0]; sys->input->userdata = (struct MMAL_PORT_USERDATA_T *)filter; if (filter->fmt_in.i_codec == VLC_CODEC_MMAL_OPAQUE) sys->input->format->encoding = MMAL_ENCODING_OPAQUE; sys->input->format->es->video.width = filter->fmt_in.video.i_width; sys->input->format->es->video.height = filter->fmt_in.video.i_height; sys->input->format->es->video.crop.x = 0; sys->input->format->es->video.crop.y = 0; sys->input->format->es->video.crop.width = filter->fmt_in.video.i_width; sys->input->format->es->video.crop.height = filter->fmt_in.video.i_height; sys->input->format->es->video.par.num = filter->fmt_in.video.i_sar_num; sys->input->format->es->video.par.den = filter->fmt_in.video.i_sar_den; es_format_Copy(&filter->fmt_out, &filter->fmt_in); filter->fmt_out.video.i_frame_rate *= 2; status = mmal_port_format_commit(sys->input); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to commit format for input port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->input->buffer_size = sys->input->buffer_size_recommended; sys->input->buffer_num = sys->input->buffer_num_recommended; if (filter->fmt_in.i_codec == VLC_CODEC_MMAL_OPAQUE) { MMAL_PARAMETER_BOOLEAN_T zero_copy = { { MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T) }, 1 }; status = mmal_port_parameter_set(sys->input, &zero_copy.hdr); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to set zero copy on port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); goto out; } } status = mmal_port_enable(sys->input, input_port_cb); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to enable input port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->output = sys->component->output[0]; sys->output->userdata = (struct MMAL_PORT_USERDATA_T *)filter; mmal_format_full_copy(sys->output->format, sys->input->format); status = mmal_port_format_commit(sys->output); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to commit format for output port %s (status=%"PRIx32" %s)", sys->input->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->output->buffer_num = 3; if (filter->fmt_in.i_codec == VLC_CODEC_MMAL_OPAQUE) { MMAL_PARAMETER_BOOLEAN_T zero_copy = { { MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T) }, 1 }; status = mmal_port_parameter_set(sys->output, &zero_copy.hdr); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to set zero copy on port %s (status=%"PRIx32" %s)", sys->output->name, status, mmal_status_to_string(status)); goto out; } } status = mmal_port_enable(sys->output, output_port_cb); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to enable output port %s (status=%"PRIx32" %s)", sys->output->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } status = mmal_component_enable(sys->component); if (status != MMAL_SUCCESS) { msg_Err(filter, "Failed to enable component %s (status=%"PRIx32" %s)", sys->component->name, status, mmal_status_to_string(status)); ret = VLC_EGENERIC; goto out; } sys->filtered_pictures = mmal_queue_create(); filter->pf_video_filter = deinterlace; filter->pf_video_flush = flush; vlc_mutex_init_recursive(&sys->mutex); vlc_mutex_init(&sys->buffer_cond_mutex); vlc_cond_init(&sys->buffer_cond); out: if (ret != VLC_SUCCESS) Close(filter); return ret; }
MMAL_COMPONENT_T* CCamera::createCameraComponentAndSetupPorts() { 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 camera component status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera); if (status != MMAL_SUCCESS) { printf("Failed to create camera component\n"); return NULL; } //check we have output ports if (!camera->output_num) { printf("Camera doesn't have output ports"); mmal_component_destroy(camera); return NULL; } //get the 3 ports 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, CameraControlCallback); if (status != MMAL_SUCCESS) { printf("Unable to enable control port : error %d", status); mmal_component_destroy(camera); return NULL; } // set up the camera configuration { MMAL_PARAMETER_CAMERA_CONFIG_T cam_config; cam_config.hdr.id = MMAL_PARAMETER_CAMERA_CONFIG; cam_config.hdr.size = sizeof(cam_config); cam_config.max_stills_w = Width; cam_config.max_stills_h = Height; cam_config.stills_yuv422 = 0; cam_config.one_shot_stills = 0; cam_config.max_preview_video_w = Width; cam_config.max_preview_video_h = Height; cam_config.num_preview_video_frames = 3; cam_config.stills_capture_circular_buffer_height = 0; cam_config.fast_preview_resume = 0; cam_config.use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RESET_STC; mmal_port_parameter_set(camera->control, &cam_config.hdr); } // setup preview port format - QUESTION: Needed if we aren't using preview? format = preview_port->format; format->encoding = MMAL_ENCODING_OPAQUE; format->encoding_variant = MMAL_ENCODING_I420; format->es->video.width = Width; format->es->video.height = Height; format->es->video.crop.x = 0; format->es->video.crop.y = 0; format->es->video.crop.width = Width; format->es->video.crop.height = Height; format->es->video.frame_rate.num = FrameRate; format->es->video.frame_rate.den = 1; status = mmal_port_format_commit(preview_port); if (status != MMAL_SUCCESS) { printf("Couldn't set preview port format : error %d", status); mmal_component_destroy(camera); return NULL; } //setup video port format format = video_port->format; format->encoding = MMAL_ENCODING_I420; format->encoding_variant = MMAL_ENCODING_I420; format->es->video.width = Width; format->es->video.height = Height; format->es->video.crop.x = 0; format->es->video.crop.y = 0; format->es->video.crop.width = Width; format->es->video.crop.height = Height; format->es->video.frame_rate.num = FrameRate; format->es->video.frame_rate.den = 1; status = mmal_port_format_commit(video_port); if (status != MMAL_SUCCESS) { printf("Couldn't set video port format : error %d", status); mmal_component_destroy(camera); return NULL; } //setup still port format format = still_port->format; format->encoding = MMAL_ENCODING_OPAQUE; format->encoding_variant = MMAL_ENCODING_I420; format->es->video.width = Width; format->es->video.height = Height; format->es->video.crop.x = 0; format->es->video.crop.y = 0; format->es->video.crop.width = Width; format->es->video.crop.height = 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) { printf("Couldn't set still port format : error %d", status); mmal_component_destroy(camera); return NULL; } //apply all camera parameters raspicamcontrol_set_all_parameters(camera, &CameraParameters); //enable the camera status = mmal_component_enable(camera); if (status != MMAL_SUCCESS) { printf("Couldn't enable camera\n"); mmal_component_destroy(camera); return NULL; } return camera; }
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; }
/** * 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 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; }
/** * 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; }
/** * 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; }
int Private_Impl_Still::createCamera() { if ( mmal_component_create ( MMAL_COMPONENT_DEFAULT_CAMERA, &camera ) ) { cout << API_NAME << ": Failed to create camera component.\n"; destroyCamera(); return -1; } if ( !camera->output_num ) { cout << API_NAME << ": Camera does not have output ports!\n"; destroyCamera(); return -1; } camera_still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT]; // Enable the camera, and tell it its control callback function if ( mmal_port_enable ( camera->control, control_callback ) ) { cout << API_NAME << ": Could not enable control port.\n"; destroyCamera(); return -1; } MMAL_PARAMETER_CAMERA_CONFIG_T camConfig = { {MMAL_PARAMETER_CAMERA_CONFIG, sizeof ( camConfig ) }, width, // max_stills_w height, // max_stills_h 0, // stills_yuv422 1, // one_shot_stills width, // max_preview_video_w height, // max_preview_video_h 3, // num_preview_video_frames 0, // stills_capture_circular_buffer_height 0, // fast_preview_resume MMAL_PARAM_TIMESTAMP_MODE_RESET_STC // use_stc_timestamp }; if ( mmal_port_parameter_set ( camera->control, &camConfig.hdr ) != MMAL_SUCCESS ) cout << API_NAME << ": Could not set port parameters.\n"; commitParameters(); MMAL_ES_FORMAT_T * format = camera_still_port->format; format->encoding = MMAL_ENCODING_OPAQUE; format->es->video.width = width; format->es->video.height = height; format->es->video.crop.x = 0; format->es->video.crop.y = 0; format->es->video.crop.width = width; format->es->video.crop.height = height; format->es->video.frame_rate.num = STILLS_FRAME_RATE_NUM; format->es->video.frame_rate.den = STILLS_FRAME_RATE_DEN; if ( camera_still_port->buffer_size < camera_still_port->buffer_size_min ) camera_still_port->buffer_size = camera_still_port->buffer_size_min; camera_still_port->buffer_num = camera_still_port->buffer_num_recommended; if ( mmal_port_format_commit ( camera_still_port ) ) { cout << API_NAME << ": Camera still format could not be set.\n"; destroyCamera(); return -1; } if ( mmal_component_enable ( camera ) ) { cout << API_NAME << ": Camera component could not be enabled.\n"; destroyCamera(); return -1; } if ( ! ( encoder_pool = mmal_port_pool_create ( camera_still_port, camera_still_port->buffer_num, camera_still_port->buffer_size ) ) ) { cout << API_NAME << ": Failed to create buffer header pool for camera.\n"; destroyCamera(); return -1; } return 0; }
PiCam::PiCam(unsigned int width, unsigned int height, std::function<void(cv::Mat)> callback) : width(width), height(height), callback(callback), videoPool(videoPool), cameraComponent(nullptr), previewPort(nullptr), videoPort(nullptr), stillPort(nullptr) { bcm_host_init(); std::cout << "BCM HOST INIT Finished" << std::endl; MMAL_STATUS_T status; status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &cameraComponent); if(status != MMAL_SUCCESS) throw std::runtime_error("Couldn't create camera component."); if(!cameraComponent->output_num) throw std::runtime_error("Camera doesn't have output ports."); videoPort = cameraComponent->output[MMAL_CAMERA_VIDEO_PORT]; stillPort = cameraComponent->output[MMAL_CAMERA_CAPTURE_PORT]; { MMAL_PARAMETER_CAMERA_CONFIG_T cam_config = { { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) }, .max_stills_w = width, .max_stills_h = height, .stills_yuv422 = 0, .one_shot_stills = 0, .max_preview_video_w = width, .max_preview_video_h = 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(cameraComponent->control, &cam_config.hdr); } // Setup format for the video port. MMAL_ES_FORMAT_T* format = videoPort->format; format->encoding = MMAL_ENCODING_BGR24; format->encoding_variant = MMAL_ENCODING_BGR24; //format->encoding = MMAL_ENCODING_I420; //format->encoding_variant = MMAL_ENCODING_I420; format->es->video.width = width; format->es->video.height = height; format->es->video.crop.x = 0; format->es->video.crop.y = 0; format->es->video.crop.width = width; format->es->video.crop.height = height; format->es->video.frame_rate.num = framerate; format->es->video.frame_rate.den = VIDEO_FRAME_RATE_DEN; status = mmal_port_format_commit(videoPort); if(status) throw std::runtime_error("Couldn't set video format."); status = mmal_port_enable(videoPort, PiCam::video_buffer_callback); if(status) throw std::runtime_error("Couldn't enable video buffer callback"); if (videoPort->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM) videoPort->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM; // Setup format for the still port. format = stillPort->format; format->encoding = MMAL_ENCODING_OPAQUE; format->encoding_variant = MMAL_ENCODING_I420; format->es->video.width = width; format->es->video.height = height; format->es->video.crop.x = 0; format->es->video.crop.y = 0; format->es->video.crop.width = width; format->es->video.crop.height = height; format->es->video.frame_rate.num = 1; format->es->video.frame_rate.den = 1; status = mmal_port_format_commit(stillPort); if(status) throw std::runtime_error("Couldn't set still format."); // Ensure there are enough buffers to avoid dropping frames. if (stillPort->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM) stillPort->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM; videoPort->buffer_size = videoPort->buffer_size_recommended; videoPort->buffer_num = videoPort->buffer_num_recommended; videoPool = mmal_port_pool_create(videoPort, videoPort->buffer_num, videoPort->buffer_size); if(!videoPool) throw std::runtime_error("Couldn't create buffer header pool for video output port"); MMAL_PARAMETER_EXPOSUREMODE_T exp_mode = {{MMAL_PARAMETER_EXPOSURE_MODE,sizeof(exp_mode)}, MMAL_PARAM_EXPOSUREMODE_FIXEDFPS}; status = mmal_port_parameter_set(cameraComponent->control, &exp_mode.hdr); status = mmal_component_enable(cameraComponent); // frame = cv::Mat(height, width, CV_8UC3); videoPort->userdata = (struct MMAL_PORT_USERDATA_T*)this; /* if (mmal_port_parameter_set_boolean(videoPort, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS) { throw std::runtime_error("Couldn't start video capture"); } int num = mmal_queue_length(videoPool->queue); int q; for (q=0;q<num;q++) { MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(videoPool->queue); // TODO: Add numbers to these error messages. if (!buffer) throw std::runtime_error("Unable to get a required buffer from pool queue"); if (mmal_port_send_buffer(videoPort, buffer)!= MMAL_SUCCESS) throw std::runtime_error("Unable to send a buffer to an encoder output port"); } */ }
static av_cold int ffmmal_init_decoder(AVCodecContext *avctx) { MMALDecodeContext *ctx = avctx->priv_data; MMAL_STATUS_T status; MMAL_ES_FORMAT_T *format_in; MMAL_COMPONENT_T *decoder; char tmp[32]; int ret = 0; bcm_host_init(); if (mmal_vc_init()) { av_log(avctx, AV_LOG_ERROR, "Cannot initialize MMAL VC driver!\n"); return AVERROR(ENOSYS); } if ((ret = ff_get_format(avctx, avctx->codec->pix_fmts)) < 0) return ret; avctx->pix_fmt = ret; if ((status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &ctx->decoder))) goto fail; decoder = ctx->decoder; format_in = decoder->input[0]->format; format_in->type = MMAL_ES_TYPE_VIDEO; switch (avctx->codec_id) { case AV_CODEC_ID_MPEG2VIDEO: format_in->encoding = MMAL_ENCODING_MP2V; break; case AV_CODEC_ID_MPEG4: format_in->encoding = MMAL_ENCODING_MP4V; break; case AV_CODEC_ID_VC1: format_in->encoding = MMAL_ENCODING_WVC1; break; case AV_CODEC_ID_H264: default: format_in->encoding = MMAL_ENCODING_H264; break; } format_in->es->video.width = FFALIGN(avctx->width, 32); format_in->es->video.height = FFALIGN(avctx->height, 16); format_in->es->video.crop.width = avctx->width; format_in->es->video.crop.height = avctx->height; format_in->es->video.frame_rate.num = 24000; format_in->es->video.frame_rate.den = 1001; format_in->es->video.par.num = avctx->sample_aspect_ratio.num; format_in->es->video.par.den = avctx->sample_aspect_ratio.den; format_in->flags = MMAL_ES_FORMAT_FLAG_FRAMED; av_get_codec_tag_string(tmp, sizeof(tmp), format_in->encoding); av_log(avctx, AV_LOG_DEBUG, "Using MMAL %s encoding.\n", tmp); #if HAVE_MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS if (mmal_port_parameter_set_uint32(decoder->input[0], MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS, -1 - ctx->extra_decoder_buffers)) { av_log(avctx, AV_LOG_WARNING, "Could not set input buffering limit.\n"); } #endif if ((status = mmal_port_format_commit(decoder->input[0]))) goto fail; decoder->input[0]->buffer_num = FFMAX(decoder->input[0]->buffer_num_min, 20); decoder->input[0]->buffer_size = FFMAX(decoder->input[0]->buffer_size_min, 512 * 1024); ctx->pool_in = mmal_pool_create(decoder->input[0]->buffer_num, 0); if (!ctx->pool_in) { ret = AVERROR(ENOMEM); goto fail; } if ((ret = ffmal_update_format(avctx)) < 0) goto fail; ctx->queue_decoded_frames = mmal_queue_create(); if (!ctx->queue_decoded_frames) goto fail; decoder->input[0]->userdata = (void*)avctx; decoder->output[0]->userdata = (void*)avctx; decoder->control->userdata = (void*)avctx; if ((status = mmal_port_enable(decoder->control, control_port_cb))) goto fail; if ((status = mmal_port_enable(decoder->input[0], input_callback))) goto fail; if ((status = mmal_port_enable(decoder->output[0], output_callback))) goto fail; if ((status = mmal_component_enable(decoder))) goto fail; return 0; fail: ffmmal_close_decoder(avctx); return ret < 0 ? ret : AVERROR_UNKNOWN; }
/** * 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; }
// Fetch a decoded buffer and place it into the frame parameter. static int ffmmal_read_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame) { MMALDecodeContext *ctx = avctx->priv_data; MMAL_BUFFER_HEADER_T *buffer = NULL; MMAL_STATUS_T status = 0; int ret = 0; if (ctx->eos_received) goto done; while (1) { // To ensure decoding in lockstep with a constant delay between fed packets // and output frames, we always wait until an output buffer is available. // Except during start we don't know after how many input packets the decoder // is going to return the first buffer, and we can't distinguish decoder // being busy from decoder waiting for input. So just poll at the start and // keep feeding new data to the buffer. // We are pretty sure the decoder will produce output if we sent more input // frames than what a H.264 decoder could logically delay. This avoids too // excessive buffering. // We also wait if we sent eos, but didn't receive it yet (think of decoding // stream with a very low number of frames). if (avpriv_atomic_int_get(&ctx->packets_buffered) > MAX_DELAYED_FRAMES || (ctx->packets_sent && ctx->eos_sent)) { // MMAL will ignore broken input packets, which means the frame we // expect here may never arrive. Dealing with this correctly is // complicated, so here's a hack to avoid that it freezes forever // in this unlikely situation. buffer = mmal_queue_timedwait(ctx->queue_decoded_frames, 100); if (!buffer) { av_log(avctx, AV_LOG_ERROR, "Did not get output frame from MMAL.\n"); ret = AVERROR_UNKNOWN; goto done; } } else { buffer = mmal_queue_get(ctx->queue_decoded_frames); if (!buffer) goto done; } ctx->eos_received |= !!(buffer->flags & MMAL_BUFFER_HEADER_FLAG_EOS); if (ctx->eos_received) goto done; if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED) { MMAL_COMPONENT_T *decoder = ctx->decoder; MMAL_EVENT_FORMAT_CHANGED_T *ev = mmal_event_format_changed_get(buffer); MMAL_BUFFER_HEADER_T *stale_buffer; av_log(avctx, AV_LOG_INFO, "Changing output format.\n"); if ((status = mmal_port_disable(decoder->output[0]))) goto done; while ((stale_buffer = mmal_queue_get(ctx->queue_decoded_frames))) mmal_buffer_header_release(stale_buffer); mmal_format_copy(decoder->output[0]->format, ev->format); if ((ret = ffmal_update_format(avctx)) < 0) goto done; if ((status = mmal_port_enable(decoder->output[0], output_callback))) goto done; if ((ret = ffmmal_fill_output_port(avctx)) < 0) goto done; if ((ret = ffmmal_fill_input_port(avctx)) < 0) goto done; mmal_buffer_header_release(buffer); continue; } else if (buffer->cmd) { char s[20]; av_get_codec_tag_string(s, sizeof(s), buffer->cmd); av_log(avctx, AV_LOG_WARNING, "Unknown MMAL event %s on output port\n", s); goto done; } else if (buffer->length == 0) { // Unused output buffer that got drained after format change. mmal_buffer_header_release(buffer); continue; } ctx->frames_output++; if ((ret = ffmal_copy_frame(avctx, frame, buffer)) < 0) goto done; *got_frame = 1; break; } done: if (buffer) mmal_buffer_header_release(buffer); if (status && ret >= 0) ret = AVERROR_UNKNOWN; return ret; }
/** * 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; }