rpicamsrc: Initial caps nego and properties.

Support caps negotiation for H.264 frame size and framerate.

Add bitrate, saturation, brightness, contrast, sharpness properties.
This commit is contained in:
Jan Schmidt 2013-10-13 01:20:51 +11:00 committed by Tim-Philipp Müller
parent 1416631df9
commit cde8b33199
5 changed files with 328 additions and 215 deletions

View file

@ -565,6 +565,7 @@ void raspicamcontrol_display_help()
fprintf(stderr, "\n");
}
#endif
/**
* Dump contents of camera parameter structure to stdout for debugging/verbose logging
*
@ -572,19 +573,18 @@ void raspicamcontrol_display_help()
*/
void raspicamcontrol_dump_parameters(const RASPICAM_CAMERA_PARAMETERS *params)
{
const char *exp_mode = raspicli_unmap_xref(params->exposureMode, exposure_map, exposure_map_size);
const char *awb_mode = raspicli_unmap_xref(params->awbMode, awb_map, awb_map_size);
const char *image_effect = raspicli_unmap_xref(params->imageEffect, imagefx_map, imagefx_map_size);
const char *metering_mode = raspicli_unmap_xref(params->exposureMeterMode, metering_mode_map, metering_mode_map_size);
//const char *exp_mode = raspicli_unmap_xref(params->exposureMode, exposure_map, exposure_map_size);
//const char *awb_mode = raspicli_unmap_xref(params->awbMode, awb_map, awb_map_size);
//const char *image_effect = raspicli_unmap_xref(params->imageEffect, imagefx_map, imagefx_map_size);
//const char *metering_mode = raspicli_unmap_xref(params->exposureMeterMode, metering_mode_map, metering_mode_map_size);
fprintf(stderr, "Sharpness %d, Contrast %d, Brightness %d\n", params->sharpness, params->contrast, params->brightness);
fprintf(stderr, "Saturation %d, ISO %d, Video Stabilisation %s, Exposure compensation %d\n", params->saturation, params->ISO, params->videoStabilisation ? "Yes": "No", params->exposureCompensation);
fprintf(stderr, "Exposure Mode '%s', AWB Mode '%s', Image Effect '%s'\n", exp_mode, awb_mode, image_effect);
fprintf(stderr, "Metering Mode '%s', Colour Effect Enabled %s with U = %d, V = %d\n", metering_mode, params->colourEffects.enable ? "Yes":"No", params->colourEffects.u, params->colourEffects.v);
//fprintf(stderr, "Exposure Mode '%s', AWB Mode '%s', Image Effect '%s'\n", exp_mode, awb_mode, image_effect);
//fprintf(stderr, "Metering Mode '%s', Colour Effect Enabled %s with U = %d, V = %d\n", metering_mode, params->colourEffects.enable ? "Yes":"No", params->colourEffects.u, params->colourEffects.v);
fprintf(stderr, "Rotation %d, hflip %s, vflip %s\n", params->rotation, params->hflip ? "Yes":"No",params->vflip ? "Yes":"No");
fprintf(stderr, "ROI x %lf, y %f, w %f h %f\n", params->roi.x, params->roi.y, params->roi.w, params->roi.h);
}
#endif
/**
* Convert a MMAL status return value to a simple boolean of success

View file

@ -110,7 +110,7 @@ typedef struct
struct RASPIVID_STATE_T
{
RASPIVID_CONFIG config;
RASPIVID_CONFIG *config;
FILE *output_file;
@ -119,6 +119,7 @@ struct RASPIVID_STATE_T
MMAL_CONNECTION_T *preview_connection; /// Pointer to the connection from camera to preview
MMAL_CONNECTION_T *encoder_connection; /// Pointer to the connection from camera to encoder
MMAL_PORT_T *camera_video_port;
MMAL_PORT_T *camera_still_port;
MMAL_PORT_T *encoder_output_port;
@ -164,7 +165,6 @@ static COMMAND_LIST cmdline_commands[] =
{ CommandWidth, "-width", "w", "Set image width <size>. Default 1920", 1 },
{ CommandHeight, "-height", "h", "Set image height <size>. Default 1080", 1 },
{ CommandBitrate, "-bitrate", "b", "Set bitrate. Use bits per second (e.g. 10MBits/s would be -b 10000000)", 1 },
{ CommandOutput, "-output", "o", "Output filename <filename> (to write to stdout, use '-o -')", 1 },
{ CommandVerbose, "-verbose", "v", "Output verbose information during run", 0 },
{ CommandTimeout, "-timeout", "t", "Time (in ms) to capture for. If not specified, set to 5s. Zero to disable", 1 },
{ CommandDemoMode,"-demo", "d", "Run a demo mode (cycle through range of camera options, no capture)", 1},
@ -192,7 +192,8 @@ void raspicapture_default_config(RASPIVID_CONFIG *config)
config->width = 1920; // Default to 1080p
config->height = 1080;
config->bitrate = 17000000; // This is a decent default bitrate for 1080p
config->framerate = VIDEO_FRAME_RATE_NUM;
config->fps_n = VIDEO_FRAME_RATE_NUM;
config->fps_d = VIDEO_FRAME_RATE_DEN;
config->intraperiod = 0; // Not set
config->demoMode = 0;
config->demoInterval = 250; // ms
@ -220,12 +221,12 @@ static void dump_state(RASPIVID_STATE *state)
return;
}
fprintf(stderr, "Width %d, Height %d, filename %s\n", state->config.width, state->config.height, state->config.filename);
fprintf(stderr, "bitrate %d, framerate %d, time delay %d\n", state->config.bitrate, state->config.framerate, state->config.timeout);
//fprintf(stderr, "H264 Profile %s\n", raspicli_unmap_xref(state->config.profile, profile_map, profile_map_size));
fprintf(stderr, "Width %d, Height %d\n", state->config->width, state->config->height);
fprintf(stderr, "bitrate %d, framerate %d/%d, time delay %d\n", state->config->bitrate, state->config->fps_n, state->config->fps_d, state->config->timeout);
//fprintf(stderr, "H264 Profile %s\n", raspicli_unmap_xref(state->config->profile, profile_map, profile_map_size));
raspipreview_dump_parameters(&state->config.preview_parameters);
//raspicamcontrol_dump_parameters(&state->config.camera_parameters);
raspipreview_dump_parameters(&state->config->preview_parameters);
raspicamcontrol_dump_parameters(&state->config->camera_parameters);
}
#if 0
@ -426,12 +427,6 @@ static int parse_cmdline(int argc, const char **argv, RASPIVID_STATE *state)
return 1;
}
// Always disable verbose if output going to stdout
if (state->filename && state->filename[0] == '-')
{
state->verbose = 0;
}
return 0;
}
@ -531,7 +526,6 @@ raspi_capture_fill_buffer(RASPIVID_STATE *state, GstBuffer **bufp)
buf = gst_buffer_new_allocate(NULL, buffer->length, NULL);
if (buf) {
gst_buffer_fill(buf, 0, buffer->data, buffer->length);
g_print("Buffer of size %u\n", (guint) buffer->length);
ret = GST_FLOW_OK;
}
@ -569,9 +563,7 @@ raspi_capture_fill_buffer(RASPIVID_STATE *state, GstBuffer **bufp)
*/
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_COMPONENT_T *camera = NULL;
MMAL_STATUS_T status;
/* Create the component */
@ -590,9 +582,6 @@ static MMAL_STATUS_T create_camera_component(RASPIVID_STATE *state)
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);
@ -603,24 +592,48 @@ static MMAL_STATUS_T create_camera_component(RASPIVID_STATE *state)
goto error;
}
state->camera_component = camera;
return status;
error:
if (camera)
mmal_component_destroy(camera);
return status;
}
MMAL_STATUS_T
raspi_capture_set_format_and_start(RASPIVID_STATE *state)
{
MMAL_COMPONENT_T *camera = NULL;
MMAL_STATUS_T status;
MMAL_ES_FORMAT_T *format;
MMAL_PORT_T *preview_port = NULL, *video_port = NULL, *still_port = NULL;
// set up the camera configuration
MMAL_PARAMETER_CAMERA_CONFIG_T cam_config =
{
MMAL_PARAMETER_CAMERA_CONFIG_T cam_config =
{
{ MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) },
.max_stills_w = state->config.width,
.max_stills_h = state->config.height,
.stills_yuv422 = 0,
.one_shot_stills = 0,
.max_preview_video_w = state->config.width,
.max_preview_video_h = state->config.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);
}
{ MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) },
.max_stills_w = state->config->width,
.max_stills_h = state->config->height,
.stills_yuv422 = 0,
.one_shot_stills = 0,
.max_preview_video_w = state->config->width,
.max_preview_video_h = state->config->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
};
camera = state->camera_component;
preview_port = camera->output[MMAL_CAMERA_PREVIEW_PORT];
video_port = camera->output[MMAL_CAMERA_VIDEO_PORT];
still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT];
mmal_port_parameter_set(camera->control, &cam_config.hdr);
// Now set up the port formats
@ -633,14 +646,14 @@ static MMAL_STATUS_T create_camera_component(RASPIVID_STATE *state)
format->encoding_variant = MMAL_ENCODING_I420;
format->encoding = MMAL_ENCODING_OPAQUE;
format->es->video.width = state->config.width;
format->es->video.height = state->config.height;
format->es->video.width = state->config->width;
format->es->video.height = state->config->height;
format->es->video.crop.x = 0;
format->es->video.crop.y = 0;
format->es->video.crop.width = state->config.width;
format->es->video.crop.height = state->config.height;
format->es->video.frame_rate.num = state->config.framerate;
format->es->video.frame_rate.den = VIDEO_FRAME_RATE_DEN;
format->es->video.crop.width = state->config->width;
format->es->video.crop.height = state->config->height;
format->es->video.frame_rate.num = state->config->fps_n;
format->es->video.frame_rate.den = state->config->fps_d;
status = mmal_port_format_commit(preview_port);
@ -656,14 +669,14 @@ static MMAL_STATUS_T create_camera_component(RASPIVID_STATE *state)
format->encoding_variant = MMAL_ENCODING_I420;
format->encoding = MMAL_ENCODING_OPAQUE;
format->es->video.width = state->config.width;
format->es->video.height = state->config.height;
format->es->video.width = state->config->width;
format->es->video.height = state->config->height;
format->es->video.crop.x = 0;
format->es->video.crop.y = 0;
format->es->video.crop.width = state->config.width;
format->es->video.crop.height = state->config.height;
format->es->video.frame_rate.num = state->config.framerate;
format->es->video.frame_rate.den = VIDEO_FRAME_RATE_DEN;
format->es->video.crop.width = state->config->width;
format->es->video.crop.height = state->config->height;
format->es->video.frame_rate.num = state->config->fps_n;
format->es->video.frame_rate.den = state->config->fps_d;
status = mmal_port_format_commit(video_port);
@ -685,12 +698,12 @@ static MMAL_STATUS_T create_camera_component(RASPIVID_STATE *state)
format->encoding = MMAL_ENCODING_OPAQUE;
format->encoding_variant = MMAL_ENCODING_I420;
format->es->video.width = state->config.width;
format->es->video.height = state->config.height;
format->es->video.width = state->config->width;
format->es->video.height = state->config->height;
format->es->video.crop.x = 0;
format->es->video.crop.y = 0;
format->es->video.crop.width = state->config.width;
format->es->video.crop.height = state->config.height;
format->es->video.crop.width = state->config->width;
format->es->video.crop.height = state->config->height;
format->es->video.frame_rate.num = 1;
format->es->video.frame_rate.den = 1;
@ -715,20 +728,12 @@ static MMAL_STATUS_T create_camera_component(RASPIVID_STATE *state)
goto error;
}
raspicamcontrol_set_all_parameters(camera, &state->config.camera_parameters);
raspicamcontrol_set_all_parameters(camera, &state->config->camera_parameters);
state->camera_component = camera;
if (state->config.verbose)
if (state->config->verbose)
fprintf(stderr, "Camera component done\n");
return status;
error:
if (camera)
mmal_component_destroy(camera);
return status;
}
@ -786,7 +791,7 @@ static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state)
// Only supporting H264 at the moment
encoder_output->format->encoding = MMAL_ENCODING_H264;
encoder_output->format->bitrate = state->config.bitrate;
encoder_output->format->bitrate = state->config->bitrate;
encoder_output->buffer_size = encoder_output->buffer_size_recommended;
@ -823,9 +828,9 @@ static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state)
}
if (state->config.intraperiod)
if (state->config->intraperiod)
{
MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_INTRAPERIOD, sizeof(param)}, state->config.intraperiod};
MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_INTRAPERIOD, sizeof(param)}, state->config->intraperiod};
status = mmal_port_parameter_set(encoder_output, &param.hdr);
if (status != MMAL_SUCCESS)
{
@ -840,7 +845,7 @@ static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state)
param.hdr.id = MMAL_PARAMETER_PROFILE;
param.hdr.size = sizeof(param);
param.profile[0].profile = state->config.profile;
param.profile[0].profile = state->config->profile;
param.profile[0].level = MMAL_VIDEO_LEVEL_H264_4; // This is the only value supported
status = mmal_port_parameter_set(encoder_output, &param.hdr);
@ -852,7 +857,7 @@ static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state)
}
if (mmal_port_parameter_set_boolean(encoder_input, MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT, state->config.immutableInput) != MMAL_SUCCESS)
if (mmal_port_parameter_set_boolean(encoder_input, MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT, state->config->immutableInput) != MMAL_SUCCESS)
{
vcos_log_error("Unable to set immutable input flag");
// Continue rather than abort..
@ -877,7 +882,7 @@ static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state)
state->encoder_pool = pool;
state->encoder_component = encoder;
if (state->config.verbose)
if (state->config->verbose)
fprintf(stderr, "Encoder component done\n");
return status;
@ -898,8 +903,10 @@ static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state)
static void destroy_encoder_component(RASPIVID_STATE *state)
{
/* Empty the buffer header q */
while (mmal_queue_length(state->encoded_buffer_q))
(void)(mmal_queue_get(state->encoded_buffer_q));
while (mmal_queue_length(state->encoded_buffer_q)) {
MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state->encoded_buffer_q);
mmal_buffer_header_release(buffer);
}
mmal_queue_destroy(state->encoded_buffer_q);
// Get rid of any port buffers first
@ -961,29 +968,22 @@ void raspicapture_init()
}
RASPIVID_STATE *
raspi_capture_start(RASPIVID_CONFIG *config)
raspi_capture_setup(RASPIVID_CONFIG *config)
{
// Our main data storage vessel..
RASPIVID_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 *preview_input_port = NULL;
MMAL_PORT_T *encoder_input_port = NULL;
/* Default everything to zero */
state = calloc(1, sizeof(RASPIVID_STATE));
/* Apply passed in config */
state->config = *config;
if (state->config.verbose)
{
dump_state(state);
}
state->config = config;
/* So far, all we can do is create the camera component. Actual
* config and connection of encoders etc happens in _start()
*/
// OK, we have a nice set of parameters. Now set up our components
// We have three components. Camera, Preview and encoder.
@ -993,7 +993,7 @@ raspi_capture_start(RASPIVID_CONFIG *config)
return NULL;
}
if ((status = raspipreview_create(&state->config.preview_parameters)) != MMAL_SUCCESS)
if ((status = raspipreview_create(&state->config->preview_parameters)) != MMAL_SUCCESS)
{
vcos_log_error("%s: Failed to create preview component", __func__);
destroy_camera_component(state);
@ -1003,26 +1003,47 @@ raspi_capture_start(RASPIVID_CONFIG *config)
if ((status = create_encoder_component(state)) != MMAL_SUCCESS)
{
vcos_log_error("%s: Failed to create encode component", __func__);
raspipreview_destroy(&state->config.preview_parameters);
raspipreview_destroy(&state->config->preview_parameters);
destroy_camera_component(state);
return NULL;
}
if (state->config.verbose)
state->encoded_buffer_q = mmal_queue_create();
return state;
}
gboolean
raspi_capture_start(RASPIVID_STATE *state)
{
MMAL_STATUS_T status = MMAL_SUCCESS;
MMAL_PORT_T *camera_preview_port = NULL;
MMAL_PORT_T *preview_input_port = NULL;
MMAL_PORT_T *encoder_input_port = NULL;
if (state->config->verbose)
{
dump_state(state);
}
if ((status = raspi_capture_set_format_and_start(state)) != MMAL_SUCCESS) {
return FALSE;
}
if (state->config->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];
preview_input_port = state->config.preview_parameters.preview_component->input[0];
preview_input_port = state->config->preview_parameters.preview_component->input[0];
encoder_input_port = state->encoder_component->input[0];
state->camera_video_port = state->camera_component->output[MMAL_CAMERA_VIDEO_PORT];
state->camera_still_port = state->camera_component->output[MMAL_CAMERA_CAPTURE_PORT];
state->encoder_output_port = state->encoder_component->output[0];
state->encoded_buffer_q = mmal_queue_create();
if (state->config.preview_parameters.wantPreview )
if (state->config->preview_parameters.wantPreview )
{
if (state->config.verbose)
if (state->config->verbose)
{
fprintf(stderr, "Connecting camera preview port to preview input port\n");
fprintf(stderr, "Starting video preview\n");
@ -1032,46 +1053,22 @@ raspi_capture_start(RASPIVID_CONFIG *config)
status = connect_ports(camera_preview_port, preview_input_port, &state->preview_connection);
if (status != MMAL_SUCCESS)
{
mmal_status_to_int(status);
vcos_log_error("%s: Failed to connect camera to preview", __func__);
goto error;
return FALSE;
}
}
if (state->config.verbose)
if (state->config->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);
status = connect_ports(state->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->config.filename)
{
if (state->config.filename[0] == '-')
{
state->output_file = stdout;
// Ensure we don't upset the output stream with diagnostics/info
state->config.verbose = 0;
}
else
{
if (state->config.verbose)
fprintf(stderr, "Opening output file \"%s\"\n", state->config.filename);
state->output_file = fopen(state->config.filename, "wb");
}
if (!state->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->config.filename);
}
if (state->config->preview_parameters.wantPreview )
mmal_connection_destroy(state->preview_connection);
vcos_log_error("%s: Failed to connect camera video port to encoder input", __func__);
return FALSE;
}
// Set up our userdata - this is passed though to the callback where we need the information.
@ -1080,93 +1077,75 @@ raspi_capture_start(RASPIVID_CONFIG *config)
state->encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&state->callback_data;
if (state->config.verbose)
if (state->config->verbose)
fprintf(stderr, "Enabling encoder output port\n");
// Enable the encoder output port and tell it its callback function
status = mmal_port_enable(state->encoder_output_port, encoder_buffer_callback);
if (status != MMAL_SUCCESS)
{
vcos_log_error("Failed to setup encoder output");
goto error;
}
if (state->config.demoMode)
if (state->config->demoMode)
{
// Run for the user specific time..
int num_iterations = state->config.timeout / state->config.demoInterval;
int num_iterations = state->config->timeout / state->config->demoInterval;
int i;
if (state->config.verbose)
if (state->config->verbose)
fprintf(stderr, "Running in demo mode\n");
for (i=0;state->config.timeout == 0 || i<num_iterations;i++)
for (i=0;state->config->timeout == 0 || i<num_iterations;i++)
{
raspicamcontrol_cycle_test(state->camera_component);
vcos_sleep(state->config.demoInterval);
vcos_sleep(state->config->demoInterval);
}
}
else
if (state->config->verbose)
fprintf(stderr, "Starting video capture\n");
if (mmal_port_parameter_set_boolean(state->camera_video_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS)
{
// Only encode stuff if we have a filename and it opened
if (state->output_file)
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++)
{
//int wait;
MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state->encoder_pool->queue);
if (state->config.verbose)
fprintf(stderr, "Starting video capture\n");
if (!buffer)
vcos_log_error("Unable to get a required buffer %d from pool queue", q);
if (mmal_port_parameter_set_boolean(camera_video_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS)
{
goto error;
}
if (mmal_port_send_buffer(state->encoder_output_port, buffer)!= MMAL_SUCCESS)
vcos_log_error("Unable to send a buffer to encoder output port (%d)", q);
// 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(state->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
#if 0
for (wait = 0; state->config.timeout == 0 || wait < state->config.timeout; wait+= ABORT_INTERVAL)
{
vcos_sleep(ABORT_INTERVAL);
if (state->callback_data.abort)
break;
}
if (state->config.verbose)
fprintf(stderr, "Finished capture\n");
#endif
}
else
{
#if 0
if (state->config.timeout)
vcos_sleep(state->config.timeout);
else
for (;;) vcos_sleep(ABORT_INTERVAL);
#endif
}
}
return state;
// 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
#if 0
for (wait = 0; state->config->timeout == 0 || wait < state->config->timeout; wait+= ABORT_INTERVAL)
{
vcos_sleep(ABORT_INTERVAL);
if (state->callback_data.abort)
break;
}
if (state->config->verbose)
fprintf(stderr, "Finished capture\n");
#endif
return (status == MMAL_SUCCESS);
error:
raspi_capture_stop(state);
@ -1176,23 +1155,27 @@ error:
raspicamcontrol_check_configuration(128);
}
return NULL;
return FALSE;
}
void
raspi_capture_stop(RASPIVID_STATE *state)
{
if (state->config.verbose)
if (state->config->verbose)
fprintf(stderr, "Closing down\n");
if (state->config->preview_parameters.wantPreview )
mmal_connection_destroy(state->preview_connection);
mmal_connection_destroy(state->encoder_connection);
// Disable all our ports that are not handled by connections
check_disable_port(state->camera_still_port);
check_disable_port(state->encoder_output_port);
}
if (state->config.preview_parameters.wantPreview )
mmal_connection_destroy(state->preview_connection);
mmal_connection_destroy(state->encoder_connection);
void
raspi_capture_free(RASPIVID_STATE *state)
{
// Can now close our file. Note disabling ports may flush buffers which causes
// problems if we have already closed the file!
if (state->output_file && state->output_file != stdout)
@ -1202,17 +1185,17 @@ raspi_capture_stop(RASPIVID_STATE *state)
if (state->encoder_component)
mmal_component_disable(state->encoder_component);
if (state->config.preview_parameters.preview_component)
mmal_component_disable(state->config.preview_parameters.preview_component);
if (state->config->preview_parameters.preview_component)
mmal_component_disable(state->config->preview_parameters.preview_component);
if (state->camera_component)
mmal_component_disable(state->camera_component);
destroy_encoder_component(state);
raspipreview_destroy(&state->config.preview_parameters);
raspipreview_destroy(&state->config->preview_parameters);
destroy_camera_component(state);
if (state->config.verbose)
if (state->config->verbose)
fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n");
free(state);

View file

@ -60,14 +60,14 @@ G_BEGIN_DECLS
*/
typedef struct
{
char *filename;
int verbose; /// !0 if want detailed run information
int timeout; /// Time taken before frame is grabbed and app then shuts down. Units are milliseconds
int width; /// Requested width of image
int height; /// requested height of image
int bitrate; /// Requested bitrate
int framerate; /// Requested frame rate (fps)
int fps_n; /// Requested frame rate (fps) numerator
int fps_d; /// Requested frame rate (fps) denominator
int intraperiod; /// Intra-refresh period (key frame rate)
int demoMode; /// Run app in demo mode
int demoInterval; /// Interval between camera settings changes
@ -82,9 +82,11 @@ typedef struct RASPIVID_STATE_T RASPIVID_STATE;
void raspicapture_init();
void raspicapture_default_config(RASPIVID_CONFIG *config);
RASPIVID_STATE *raspi_capture_start(RASPIVID_CONFIG *config);
RASPIVID_STATE *raspi_capture_setup(RASPIVID_CONFIG *config);
gboolean raspi_capture_start(RASPIVID_STATE *state);
GstFlowReturn raspi_capture_fill_buffer(RASPIVID_STATE *state, GstBuffer **buf);
void raspi_capture_stop(RASPIVID_STATE *state);
void raspi_capture_free(RASPIVID_STATE *state);
G_END_DECLS

View file

@ -88,8 +88,41 @@ enum
enum
{
PROP_0,
PROP_BITRATE,
PROP_SHARPNESS,
PROP_CONTRAST,
PROP_BRIGHTNESS,
PROP_SATURATION,
PROP_ISO,
PROP_VIDEO_STABILISATION,
PROP_EXPOSURE_COMPENSATION,
};
#define BITRATE_DEFAULT 17000000 /* 17Mbit/s default for 1080p */
#define BITRATE_HIGHEST 25000000
#define SHARPNESS_DEFAULT 0
#define CONTRAST_DEFAULT 0
#define BRIGHTNESS_DEFAULT 50
#define SATURATION_DEFAULT 0
#define ISO_DEFAULT 0
#define VIDEO_STABILISATION_DEFAULT FALSE
#define EXPOSURE_COMPENSATION_DEFAULT FALSE
/*
params->exposureMode = MMAL_PARAM_EXPOSUREMODE_AUTO;
params->exposureMeterMode = MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE;
params->awbMode = MMAL_PARAM_AWBMODE_AUTO;
params->imageEffect = MMAL_PARAM_IMAGEFX_NONE;
params->colourEffects.enable = 0;
params->colourEffects.u = 128;
params->colourEffects.v = 128;
params->rotation = 0;
params->hflip = params->vflip = 0;
params->roi.x = params->roi.y = 0.0;
params->roi.w = params->roi.h = 1.0;
*/
#define RAW_AND_JPEG_CAPS \
GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL) ";" \
"image/jpeg," \
@ -125,6 +158,7 @@ static gboolean gst_rpi_cam_src_decide_allocation (GstBaseSrc * src,
GstQuery * query);
static GstFlowReturn gst_rpi_cam_src_create (GstPushSrc *parent, GstBuffer **buf);
static GstCaps *gst_rpi_cam_src_get_caps (GstBaseSrc * src, GstCaps * filter);
static gboolean gst_rpi_cam_src_set_caps (GstBaseSrc * src, GstCaps *caps);
static GstCaps *gst_rpi_cam_src_fixate (GstBaseSrc * basesrc, GstCaps * caps);
static void
@ -143,6 +177,27 @@ gst_rpi_cam_src_class_init (GstRpiCamSrcClass * klass)
gobject_class->set_property = gst_rpi_cam_src_set_property;
gobject_class->get_property = gst_rpi_cam_src_get_property;
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
g_param_spec_int ("bitrate", "Bitrate", "Bitrate for encoding",
1, BITRATE_HIGHEST, BITRATE_DEFAULT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SHARPNESS,
g_param_spec_int ("sharpness", "Sharpness", "Image capture sharpness",
-100, 100, SHARPNESS_DEFAULT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CONTRAST,
g_param_spec_int ("contrast", "Contrast", "Image capture contrast",
-100, 100, CONTRAST_DEFAULT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BRIGHTNESS,
g_param_spec_int ("brightness", "Brightness", "Image capture brightness",
0, 100, BRIGHTNESS_DEFAULT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SATURATION,
g_param_spec_int ("saturation", "Saturation", "Image capture saturation",
-100, 100, SATURATION_DEFAULT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_static_metadata (gstelement_class,
"Raspberry Pi Camera Source",
"Source/Video",
@ -156,6 +211,7 @@ gst_rpi_cam_src_class_init (GstRpiCamSrcClass * klass)
basesrc_class->stop = GST_DEBUG_FUNCPTR(gst_rpi_cam_src_stop);
basesrc_class->decide_allocation = GST_DEBUG_FUNCPTR(gst_rpi_cam_src_decide_allocation);
basesrc_class->get_caps = GST_DEBUG_FUNCPTR(gst_rpi_cam_src_get_caps);
basesrc_class->set_caps = GST_DEBUG_FUNCPTR(gst_rpi_cam_src_set_caps);
basesrc_class->fixate = GST_DEBUG_FUNCPTR(gst_rpi_cam_src_fixate);
pushsrc_class->create = GST_DEBUG_FUNCPTR(gst_rpi_cam_src_create);
@ -170,8 +226,6 @@ gst_rpi_cam_src_init (GstRpiCamSrc *src)
raspicapture_default_config(&src->capture_config);
src->capture_config.verbose = 1;
src->capture_config.filename = "test.out";
}
static void
@ -181,6 +235,21 @@ gst_rpi_cam_src_set_property (GObject * object, guint prop_id,
GstRpiCamSrc *src = GST_RPICAMSRC (object);
switch (prop_id) {
case PROP_BITRATE:
src->capture_config.bitrate = g_value_get_int(value);
break;
case PROP_SHARPNESS:
src->capture_config.camera_parameters.sharpness = g_value_get_int(value);
break;
case PROP_CONTRAST:
src->capture_config.camera_parameters.contrast = g_value_get_int(value);
break;
case PROP_BRIGHTNESS:
src->capture_config.camera_parameters.brightness = g_value_get_int(value);
break;
case PROP_SATURATION:
src->capture_config.camera_parameters.saturation = g_value_get_int(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -194,6 +263,21 @@ gst_rpi_cam_src_get_property (GObject * object, guint prop_id,
GstRpiCamSrc *src = GST_RPICAMSRC (object);
switch (prop_id) {
case PROP_BITRATE:
g_value_set_int(value, src->capture_config.bitrate);
break;
case PROP_SHARPNESS:
g_value_set_int(value, src->capture_config.camera_parameters.sharpness);
break;
case PROP_CONTRAST:
g_value_set_int(value, src->capture_config.camera_parameters.contrast);
break;
case PROP_BRIGHTNESS:
g_value_set_int(value, src->capture_config.camera_parameters.brightness);
break;
case PROP_SATURATION:
g_value_set_int(value, src->capture_config.camera_parameters.saturation);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -205,7 +289,10 @@ gst_rpi_cam_src_start (GstBaseSrc *parent)
{
GstRpiCamSrc *src = GST_RPICAMSRC(parent);
g_print ("In src_start()\n");
src->capture_state = raspi_capture_start(&src->capture_config);
src->capture_state = raspi_capture_setup(&src->capture_config);
if (src->capture_state == NULL)
return FALSE;
return TRUE;
}
@ -213,17 +300,52 @@ static gboolean
gst_rpi_cam_src_stop (GstBaseSrc *parent)
{
GstRpiCamSrc *src = GST_RPICAMSRC(parent);
raspi_capture_stop(src->capture_state);
if (src->started)
raspi_capture_stop(src->capture_state);
raspi_capture_free(src->capture_state);
src->capture_state = NULL;
return TRUE;
}
static GstCaps *
gst_rpi_cam_src_get_caps (GstBaseSrc * src, GstCaps * filter)
gst_rpi_cam_src_get_caps (GstBaseSrc *bsrc, GstCaps * filter)
{
g_print ("In get_caps\n");
//if (src->state == NULL)
return gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (src));
/* Retrieve limiting parameters from the camera module, max width/height fps-range */
GstRpiCamSrc *src = GST_RPICAMSRC(bsrc);
GstCaps *caps;
caps = gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (bsrc));
if (src->capture_state == NULL)
goto done;
/* FIXME: Retrieve limiting parameters from the camera module, max width/height fps-range */
caps = gst_caps_make_writable(caps);
gst_caps_set_simple (caps,
"width", GST_TYPE_INT_RANGE, 1, 1920,
"height", GST_TYPE_INT_RANGE, 1, 1080,
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, 60, 1,
NULL);
done:
GST_DEBUG_OBJECT(src, "get_caps returning %" GST_PTR_FORMAT, caps);
return caps;
}
static gboolean
gst_rpi_cam_src_set_caps (GstBaseSrc *bsrc, GstCaps *caps)
{
GstRpiCamSrc *src = GST_RPICAMSRC(bsrc);
GstVideoInfo info;
GST_DEBUG_OBJECT (src, "In set_caps %" GST_PTR_FORMAT, caps);
if (!gst_video_info_from_caps (&info, caps))
return FALSE;
src->capture_config.width = info.width;
src->capture_config.height = info.height;
src->capture_config.fps_n = info.fps_n;
src->capture_config.fps_d = info.fps_d;
return TRUE;
}
static gboolean gst_rpi_cam_src_decide_allocation (GstBaseSrc *bsrc,
@ -245,11 +367,10 @@ static GstCaps *gst_rpi_cam_src_fixate (GstBaseSrc * basesrc, GstCaps * caps)
for (i = 0; i < gst_caps_get_size (caps); ++i) {
structure = gst_caps_get_structure (caps, i);
/* Fixate to the camera's 1920x1080 resolution if possible */
/* Fixate to 1920x1080 resolution if possible */
gst_structure_fixate_field_nearest_int (structure, "width", 1920);
gst_structure_fixate_field_nearest_int (structure, "height", 1080);
gst_structure_fixate_field_nearest_fraction (structure, "framerate",
G_MAXINT, 1);
gst_structure_fixate_field_nearest_fraction (structure, "framerate", 30, 1);
gst_structure_fixate_field (structure, "format");
}
@ -266,10 +387,16 @@ gst_rpi_cam_src_create (GstPushSrc *parent, GstBuffer **buf)
GstRpiCamSrc *src = GST_RPICAMSRC(parent);
GstFlowReturn ret;
if (!src->started) {
if (!raspi_capture_start(src->capture_state))
return GST_FLOW_ERROR;
src->started = TRUE;
}
/* FIXME: Use custom allocator */
ret = raspi_capture_fill_buffer(src->capture_state, buf);
if (*buf)
g_print ("Made buffer of size %" G_GSIZE_FORMAT "\n", gst_buffer_get_size(*buf));
GST_LOG_OBJECT(src, "Made buffer of size %" G_GSIZE_FORMAT "\n", gst_buffer_get_size(*buf));
return ret;
}

View file

@ -71,6 +71,7 @@ struct _GstRpiCamSrc
RASPIVID_CONFIG capture_config;
RASPIVID_STATE *capture_state;
gboolean started;
};
struct _GstRpiCamSrcClass