rpicamsrc: Update properties dynamically where possible
authorJan Schmidt <jan@centricular.com>
Sun, 26 Apr 2015 14:54:54 +0000 (00:54 +1000)
committerTim-Philipp Müller <tim@centricular.com>
Fri, 10 Jul 2020 15:44:23 +0000 (16:44 +0100)
Update camera and encoder properties at runtime
where possible

Fixes https://github.com/thaytan/gst-rpicamsrc/issues/19
and https://github.com/thaytan/gst-rpicamsrc/issues/23

sys/rpicamsrc/RaspiCapture.c
sys/rpicamsrc/RaspiCapture.h
sys/rpicamsrc/gstrpicamsrc.c
sys/rpicamsrc/gstrpicamsrc.h

index 34194fb..a81b750 100644 (file)
@@ -111,7 +111,7 @@ typedef struct
 
 struct RASPIVID_STATE_T
 {
-   RASPIVID_CONFIG *config;
+   RASPIVID_CONFIG config;
 
    FILE *output_file;
 
@@ -132,6 +132,8 @@ struct RASPIVID_STATE_T
 
    int64_t base_time;
    int64_t last_second;
+
+   RASPIPREVIEW_STATE preview_state;
 };
 
 
@@ -294,18 +296,23 @@ void raspicapture_default_config(RASPIVID_CONFIG *config)
  */
 static void dump_state(RASPIVID_STATE *state)
 {
+   RASPIVID_CONFIG *config;
+
    if (!state)
    {
       vcos_assert(0);
       return;
    }
 
-   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));
+   config = &state->config;
 
-   raspipreview_dump_parameters(&state->config->preview_parameters);
-   raspicamcontrol_dump_parameters(&state->config->camera_parameters);
+   fprintf(stderr, "Width %d, Height %d\n", config->width, config->height);
+   fprintf(stderr, "bitrate %d, framerate %d/%d, time delay %d\n",
+       config->bitrate, config->fps_n, config->fps_d, config->timeout);
+   //fprintf(stderr, "H264 Profile %s\n", raspicli_unmap_xref(config->profile, profile_map, profile_map_size));
+
+   raspipreview_dump_parameters(&config->preview_parameters);
+   raspicamcontrol_dump_parameters(&config->camera_parameters);
 }
 
 #if 0
@@ -623,7 +630,7 @@ static int parse_cmdline(int argc, const char **argv, RASPIVID_STATE *state)
 
       case CommandIntraRefreshType:
       {
-         state->config->intra_refresh_type = raspicli_map_xref(argv[i + 1], intra_refresh_map, intra_refresh_map_size);
+         state->config.intra_refresh_type = raspicli_map_xref(argv[i + 1], intra_refresh_map, intra_refresh_map_size);
          i++;
          break;
       }
@@ -843,7 +850,7 @@ static FILE *open_imv_filename(RASPIVID_STATE *pState)
  */
 static void update_annotation_data(RASPIVID_STATE *state)
 {
-   RASPIVID_CONFIG *config = state->config;
+   RASPIVID_CONFIG *config = &state->config;
 
    // So, if we have asked for a application supplied string, set it to the H264 parameters
    if (config->camera_parameters.enable_annotate & ANNOTATE_APP_TEXT)
@@ -930,7 +937,7 @@ raspi_capture_fill_buffer(RASPIVID_STATE *state, GstBuffer **bufp,
   /* FIXME: Use our own interruptible cond wait: */
   buffer = mmal_queue_wait(state->encoded_buffer_q);
 
-  
+
   if (G_LIKELY (clock)) {
     MMAL_PARAMETER_INT64_T param;
     GstClockTime runtime;
@@ -1000,7 +1007,7 @@ static MMAL_STATUS_T create_camera_component(RASPIVID_STATE *state)
 {
    MMAL_COMPONENT_T *camera = NULL;
    MMAL_STATUS_T status;
-   RASPIVID_CONFIG *config = state->config;
+   RASPIVID_CONFIG *config = &state->config;
 
    /* Create the component */
    status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera);
@@ -1077,7 +1084,7 @@ raspi_capture_set_format_and_start(RASPIVID_STATE *state)
    MMAL_STATUS_T status;
    MMAL_ES_FORMAT_T *format;
    MMAL_PORT_T *preview_port = NULL, *video_port = NULL, *still_port = NULL;
-   RASPIVID_CONFIG *config = state->config;
+   RASPIVID_CONFIG *config = &state->config;
 
    //  set up the camera configuration
 
@@ -1294,7 +1301,7 @@ static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state)
    MMAL_PORT_T *encoder_input = NULL, *encoder_output = NULL;
    MMAL_STATUS_T status;
    MMAL_POOL_T *pool;
-   RASPIVID_CONFIG *config = state->config;
+   RASPIVID_CONFIG *config = &state->config;
 
    status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER, &encoder);
 
@@ -1363,7 +1370,7 @@ static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state)
 
    if (config->intraperiod != -1)
    {
-      MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_INTRAPERIOD, sizeof(param)}, state->config->intraperiod};
+      MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_INTRAPERIOD, sizeof(param)}, config->intraperiod};
       status = mmal_port_parameter_set(encoder_output, &param.hdr);
       if (status != MMAL_SUCCESS)
       {
@@ -1374,7 +1381,7 @@ static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state)
 
    if (config->quantisationParameter)
    {
-      MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT, sizeof(param)}, state->config->quantisationParameter};
+      MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT, sizeof(param)}, config->quantisationParameter};
       status = mmal_port_parameter_set(encoder_output, &param.hdr);
       if (status != MMAL_SUCCESS)
       {
@@ -1587,7 +1594,7 @@ raspi_capture_setup(RASPIVID_CONFIG *config)
   state = calloc(1, sizeof(RASPIVID_STATE));
 
   /* Apply passed in config */
-  state->config = config;
+  state->config = *config;
 
   /* Initialize timestamping */
   state->base_time = state->last_second = -1;
@@ -1604,7 +1611,7 @@ raspi_capture_setup(RASPIVID_CONFIG *config)
      return NULL;
   }
 
-  if ((status = raspipreview_create(&state->config->preview_parameters)) != MMAL_SUCCESS)
+  if ((status = raspipreview_create(&state->preview_state, &config->preview_parameters)) != MMAL_SUCCESS)
   {
      vcos_log_error("%s: Failed to create preview component", __func__);
      destroy_camera_component(state);
@@ -1620,6 +1627,8 @@ gboolean
 raspi_capture_start(RASPIVID_STATE *state)
 {
   MMAL_STATUS_T status = MMAL_SUCCESS;
+  RASPIVID_CONFIG *config = &state->config;
+
   MMAL_PORT_T *camera_preview_port = NULL;
   MMAL_PORT_T *preview_input_port = NULL;
   MMAL_PORT_T *encoder_input_port = NULL;
@@ -1630,7 +1639,7 @@ raspi_capture_start(RASPIVID_STATE *state)
      return FALSE;
   }
 
-  if (state->config->verbose)
+  if (config->verbose)
   {
      dump_state(state);
   }
@@ -1639,20 +1648,20 @@ raspi_capture_start(RASPIVID_STATE *state)
      return FALSE;
   }
 
-  if (state->config->verbose)
+  if (state->config.verbose)
      fprintf(stderr, "Starting component connection stage\n");
 
   camera_preview_port = state->camera_component->output[MMAL_CAMERA_PREVIEW_PORT];
-  preview_input_port  = state->config->preview_parameters.preview_component->input[0];
+  preview_input_port  = state->preview_state.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];
 
-  if (state->config->preview_parameters.wantPreview )
+  if (config->preview_parameters.wantPreview )
   {
-     if (state->config->verbose)
+     if (config->verbose)
      {
         fprintf(stderr, "Connecting camera preview port to preview input port\n");
         fprintf(stderr, "Starting video preview\n");
@@ -1667,14 +1676,14 @@ raspi_capture_start(RASPIVID_STATE *state)
      }
   }
 
-  if (state->config->verbose)
+  if (config->verbose)
      fprintf(stderr, "Connecting camera stills port to encoder input port\n");
 
   // Now connect the camera to the encoder
   status = connect_ports(state->camera_video_port, encoder_input_port, &state->encoder_connection);
   if (status != MMAL_SUCCESS)
   {
-    if (state->config->preview_parameters.wantPreview )
+    if (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;
@@ -1686,7 +1695,7 @@ raspi_capture_start(RASPIVID_STATE *state)
 
   state->encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&state->callback_data;
 
-  if (state->config->verbose)
+  if (config->verbose)
      fprintf(stderr, "Enabling encoder output port\n");
 
   // Enable the encoder output port and tell it its callback function
@@ -1697,23 +1706,23 @@ raspi_capture_start(RASPIVID_STATE *state)
      goto error;
   }
 
-  if (state->config->demoMode)
+  if (config->demoMode)
   {
      // Run for the user specific time..
-     int num_iterations = state->config->timeout / state->config->demoInterval;
+     int num_iterations = config->timeout / config->demoInterval;
      int i;
 
-     if (state->config->verbose)
+     if (config->verbose)
         fprintf(stderr, "Running in demo mode\n");
 
-     for (i=0;state->config->timeout == 0 || i<num_iterations;i++)
+     for (i=0;config->timeout == 0 || i<num_iterations;i++)
      {
         raspicamcontrol_cycle_test(state->camera_component);
-        vcos_sleep(state->config->demoInterval);
+        vcos_sleep(state->config.demoInterval);
      }
   }
 
-  if (state->config->verbose)
+  if (config->verbose)
     fprintf(stderr, "Starting video capture\n");
 
   if (mmal_port_parameter_set_boolean(state->camera_video_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS)
@@ -1743,14 +1752,14 @@ raspi_capture_start(RASPIVID_STATE *state)
   // Going to check every ABORT_INTERVAL milliseconds
 
 #if 0
-  for (wait = 0; state->config->timeout == 0 || wait < state->config->timeout; wait+= ABORT_INTERVAL)
+  for (wait = 0; config->timeout == 0 || wait < config->timeout; wait+= ABORT_INTERVAL)
   {
      vcos_sleep(ABORT_INTERVAL);
      if (state->callback_data.abort)
         break;
   }
 
-  if (state->config->verbose)
+  if (config->verbose)
      fprintf(stderr, "Finished capture\n");
 #endif
 
@@ -1770,10 +1779,12 @@ error:
 void
 raspi_capture_stop(RASPIVID_STATE *state)
 {
-  if (state->config->verbose)
+   RASPIVID_CONFIG *config = &state->config;
+
+  if (config->verbose)
      fprintf(stderr, "Closing down\n");
 
-  if (state->config->preview_parameters.wantPreview )
+  if (config->preview_parameters.wantPreview )
      mmal_connection_destroy(state->preview_connection);
   mmal_connection_destroy(state->encoder_connection);
 
@@ -1790,6 +1801,8 @@ raspi_capture_stop(RASPIVID_STATE *state)
 void
 raspi_capture_free(RASPIVID_STATE *state)
 {
+   RASPIVID_CONFIG *config = &state->config;
+
   // 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)
@@ -1799,14 +1812,14 @@ raspi_capture_free(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->preview_state.preview_component)
+     mmal_component_disable(state->preview_state.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->preview_state);
   destroy_camera_component(state);
 
   if (state->encoded_buffer_q) {
@@ -1814,8 +1827,124 @@ raspi_capture_free(RASPIVID_STATE *state)
     state->encoded_buffer_q = NULL;
   }
 
-  if (state->config->verbose)
+  if (config->verbose)
      fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n");
 
   free(state);
 }
+
+void
+raspi_capture_update_config (RASPIVID_STATE *state, RASPIVID_CONFIG *config)
+{
+  MMAL_STATUS_T status;
+  RASPICAM_CAMERA_PARAMETERS *params = &config->camera_parameters;
+  MMAL_COMPONENT_T *camera = state->camera_component;
+
+  /* Store the new config */
+  state->config = *config;
+
+  if (config->change_flags & PROP_CHANGE_ENCODING) {
+    /* BITRATE or QUANT or KEY Interval, intra refresh */
+    MMAL_COMPONENT_T *encoder = state->encoder_component;
+    MMAL_PORT_T *encoder_output = encoder->output[0];
+
+    encoder_output->format->bitrate = config->bitrate;
+    status = mmal_port_format_commit(encoder_output);
+    if (status != MMAL_SUCCESS)
+      vcos_log_warn("Unable to change bitrate dynamically");
+
+    {
+      MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_INTRAPERIOD, sizeof(param)}, config->intraperiod};
+      status = mmal_port_parameter_set(encoder_output, &param.hdr);
+      if (status != MMAL_SUCCESS)
+        vcos_log_warn("Unable to change intraperiod dynamically");
+    }
+
+    {
+      MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT, sizeof(param)}, config->quantisationParameter};
+      status = mmal_port_parameter_set(encoder_output, &param.hdr);
+      if (status != MMAL_SUCCESS)
+        vcos_log_warn("Unable to change Initial Quantisation Parameter dynamically");
+
+      MMAL_PARAMETER_UINT32_T param2 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT, sizeof(param)}, config->quantisationParameter};
+      status = mmal_port_parameter_set(encoder_output, &param2.hdr);
+      if (status != MMAL_SUCCESS)
+        vcos_log_warn("Unable to change Minimum Quantisation Parameter dynamically");
+
+      MMAL_PARAMETER_UINT32_T param3 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, sizeof(param)}, config->quantisationParameter};
+      status = mmal_port_parameter_set(encoder_output, &param3.hdr);
+      if (status != MMAL_SUCCESS)
+        vcos_log_warn("Unable to change Maximum Quantisation Parameter dynamically");
+    }
+
+    {
+      // Adaptive intra refresh settings
+      MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T  param;
+      param.hdr.id = MMAL_PARAMETER_VIDEO_INTRA_REFRESH;
+      param.hdr.size = sizeof(param);
+
+      // Get first so we don't overwrite anything unexpectedly
+      status = mmal_port_parameter_get(encoder_output, &param.hdr);
+      if (state != MMAL_SUCCESS) {
+        /* Need to memset, apparently mmal_port_parameter_get()
+         * doesn't retrieve all parameters, causing random failures
+         * when we set it. On older firmware the get fails.
+         */
+        memset (&param, 0, sizeof (MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T));
+      }
+      param.refresh_mode = config->intra_refresh_type;
+
+      status = mmal_port_parameter_set(encoder_output, &param.hdr);
+      if (status != MMAL_SUCCESS)
+         vcos_log_warn("Unable to set H264 intra-refresh values dynamically");
+    }
+  }
+  if (config->change_flags & PROP_CHANGE_PREVIEW) {
+    /* Preview settings or fullscreen */
+    status = raspipreview_update_config (&state->preview_state,
+        &config->preview_parameters);
+    if (status != MMAL_SUCCESS)
+      vcos_log_warn("Unable to change preview config dynamically");
+  }
+  if (config->change_flags & PROP_CHANGE_COLOURBALANCE) {
+    raspicamcontrol_set_saturation(camera, params->saturation);
+    raspicamcontrol_set_sharpness(camera, params->sharpness);
+    raspicamcontrol_set_contrast(camera, params->contrast);
+    raspicamcontrol_set_brightness(camera, params->brightness);
+  }
+  if (config->change_flags & PROP_CHANGE_SENSOR_SETTINGS) {
+    /* ISO, EXPOSURE, SHUTTER, DRC, Sensor Mode */
+    raspicamcontrol_set_ISO(camera, params->ISO);
+    raspicamcontrol_set_exposure_compensation(camera, params->exposureCompensation);
+    raspicamcontrol_set_exposure_mode(camera, params->exposureMode);
+    raspicamcontrol_set_metering_mode(camera, params->exposureMeterMode);
+    raspicamcontrol_set_shutter_speed(camera, params->shutter_speed);
+    raspicamcontrol_set_DRC(camera, params->drc_level);
+
+    /* Can we change sensor mode on the fly? Disable if not */
+    status = mmal_port_parameter_set_uint32(camera->control,
+       MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, config->sensor_mode);
+    if (status != MMAL_SUCCESS)
+      vcos_log_warn("Unable to change sensor mode dynamically");
+  }
+  if (config->change_flags & PROP_CHANGE_VIDEO_STABILISATION) {
+    raspicamcontrol_set_video_stabilisation(camera, params->videoStabilisation);
+  }
+  if (config->change_flags & PROP_CHANGE_AWB) {
+    raspicamcontrol_set_awb_mode(camera, params->awbMode);
+    raspicamcontrol_set_awb_gains(camera, params->awb_gains_r, params->awb_gains_b);
+  }
+  if (config->change_flags & PROP_CHANGE_IMAGE_COLOUR_EFFECT) {
+    raspicamcontrol_set_imageFX(camera, params->imageEffect);
+    raspicamcontrol_set_colourFX(camera, &params->colourEffects);
+  }
+  if (config->change_flags & PROP_CHANGE_ORIENTATION) {
+    raspicamcontrol_set_rotation(camera, params->rotation);
+    raspicamcontrol_set_flips(camera, params->hflip, params->vflip);
+  }
+  if (config->change_flags & PROP_CHANGE_ROI) {
+    raspicamcontrol_set_ROI(camera, params->roi);
+  }
+  if (config->change_flags & PROP_CHANGE_ANNOTATION)
+    update_annotation_data(state);
+}
index 5a72195..940bff8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * GStreamer
- * Copyright (C) 2013 Jan Schmidt <jan@centricular.com>
+ * Copyright (C) 2013-2015 Jan Schmidt <jan@centricular.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -64,10 +64,26 @@ GST_DEBUG_CATEGORY_EXTERN (gst_rpi_cam_src_debug);
 
 G_BEGIN_DECLS
 
+typedef enum
+{
+  PROP_CHANGE_ENCODING          = (1 << 0), /* BITRATE or QUANT or KEY Interval, intra refresh */
+  PROP_CHANGE_PREVIEW           = (1 << 1), /* Preview opacity or fullscreen */
+  PROP_CHANGE_COLOURBALANCE     = (1 << 2),
+  PROP_CHANGE_SENSOR_SETTINGS   = (1 << 3), /* ISO, EXPOSURE, SHUTTER, DRC, Sensor Mode */
+  PROP_CHANGE_VIDEO_STABILISATION = (1 << 4),
+  PROP_CHANGE_AWB               = (1 << 5),
+  PROP_CHANGE_IMAGE_COLOUR_EFFECT = (1 << 6),
+  PROP_CHANGE_ORIENTATION       = (1 << 7),
+  PROP_CHANGE_ROI               = (1 << 8),
+  PROP_CHANGE_ANNOTATION        = (1 << 9)
+} RpiPropChangeFlags;
+
 /** Structure containing all state information for the current run
  */
 typedef struct
 {
+   RpiPropChangeFlags change_flags;
+
    int verbose; /// !0 if want detailed run information
 
    int timeout;                        /// Time taken before frame is grabbed and app then shuts down. Units are milliseconds
@@ -101,6 +117,7 @@ void raspicapture_init();
 void raspicapture_default_config(RASPIVID_CONFIG *config);
 RASPIVID_STATE *raspi_capture_setup(RASPIVID_CONFIG *config);
 gboolean raspi_capture_start(RASPIVID_STATE *state);
+void raspi_capture_update_config (RASPIVID_STATE *state, RASPIVID_CONFIG *config);
 GstFlowReturn raspi_capture_fill_buffer(RASPIVID_STATE *state, GstBuffer **buf,
     GstClock *clock, GstClockTime base_time);
 void raspi_capture_stop(RASPIVID_STATE *state);
index 4a6afe0..cf9c19d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * GStreamer
- * Copyright (C) 2013-2014 Jan Schmidt <jan@centricular.com>
+ * Copyright (C) 2013-2015 Jan Schmidt <jan@centricular.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -186,6 +186,8 @@ static GstStaticPadTemplate video_src_template = GST_STATIC_PAD_TEMPLATE ("src",
 #define gst_rpi_cam_src_parent_class parent_class
 G_DEFINE_TYPE (GstRpiCamSrc, gst_rpi_cam_src, GST_TYPE_PUSH_SRC);
 
+static void gst_rpi_cam_src_finalize (GObject *object);
+
 static void gst_rpi_cam_src_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec);
 static void gst_rpi_cam_src_get_property (GObject * object, guint prop_id,
@@ -249,6 +251,8 @@ gst_rpi_cam_src_class_init (GstRpiCamSrcClass * klass)
   gstelement_class = (GstElementClass *) klass;
   basesrc_class = (GstBaseSrcClass *) klass;
   pushsrc_class = (GstPushSrcClass *) klass;
+
+  gobject_class->finalize = gst_rpi_cam_src_finalize;
   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 (gobject_class, PROP_CAMERA_NUMBER,
@@ -435,111 +439,152 @@ gst_rpi_cam_src_init (GstRpiCamSrc * src)
   raspicapture_default_config (&src->capture_config);
   src->capture_config.intraperiod = KEYFRAME_INTERVAL_DEFAULT;
   src->capture_config.verbose = 1;
+
+  g_mutex_init (&src->config_lock);
+
   /* Don't let basesrc set timestamps, we'll do it using
    * buffer PTS and system times */
   gst_base_src_set_do_timestamp (GST_BASE_SRC (src), FALSE);
 }
 
 static void
+gst_rpi_cam_src_finalize (GObject *object)
+{
+  GstRpiCamSrc *src = GST_RPICAMSRC (object);
+  g_mutex_clear (&src->config_lock);
+
+  G_OBJECT_CLASS (gst_rpi_cam_src_parent_class)->finalize (object);
+}
+
+static void
 gst_rpi_cam_src_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)
 {
   GstRpiCamSrc *src = GST_RPICAMSRC (object);
+
+  g_mutex_lock (&src->config_lock);
+
   switch (prop_id) {
     case PROP_CAMERA_NUMBER:
       src->capture_config.cameraNum = g_value_get_int (value);
       break;
     case PROP_BITRATE:
       src->capture_config.bitrate = g_value_get_int (value);
+      src->capture_config.change_flags |= PROP_CHANGE_ENCODING;
       break;
     case PROP_KEYFRAME_INTERVAL:
       src->capture_config.intraperiod = g_value_get_int (value);
+      src->capture_config.change_flags |= PROP_CHANGE_ENCODING;
       break;
     case PROP_PREVIEW:
       src->capture_config.preview_parameters.wantPreview =
           g_value_get_boolean (value);
+      src->capture_config.change_flags |= PROP_CHANGE_PREVIEW;
       break;
     case PROP_PREVIEW_ENCODED:
       src->capture_config.immutableInput = g_value_get_boolean (value);
+      src->capture_config.change_flags |= PROP_CHANGE_PREVIEW;
       break;
     case PROP_FULLSCREEN:
       src->capture_config.preview_parameters.wantFullScreenPreview =
           g_value_get_boolean (value);
+      src->capture_config.change_flags |= PROP_CHANGE_PREVIEW;
       break;
     case PROP_PREVIEW_OPACITY:
       src->capture_config.preview_parameters.opacity = g_value_get_int (value);
+      src->capture_config.change_flags |= PROP_CHANGE_PREVIEW;
       break;
     case PROP_SHARPNESS:
       src->capture_config.camera_parameters.sharpness = g_value_get_int (value);
+      src->capture_config.change_flags |= PROP_CHANGE_COLOURBALANCE;
       break;
     case PROP_CONTRAST:
       src->capture_config.camera_parameters.contrast = g_value_get_int (value);
+      src->capture_config.change_flags |= PROP_CHANGE_COLOURBALANCE;
       break;
     case PROP_BRIGHTNESS:
       src->capture_config.camera_parameters.brightness =
           g_value_get_int (value);
+      src->capture_config.change_flags |= PROP_CHANGE_COLOURBALANCE;
       break;
     case PROP_SATURATION:
       src->capture_config.camera_parameters.saturation =
           g_value_get_int (value);
+      src->capture_config.change_flags |= PROP_CHANGE_COLOURBALANCE;
       break;
     case PROP_ISO:
       src->capture_config.camera_parameters.ISO = g_value_get_int (value);
+      src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS;
       break;
     case PROP_VIDEO_STABILISATION:
       src->capture_config.camera_parameters.videoStabilisation =
           g_value_get_boolean (value);
+      src->capture_config.change_flags |= PROP_CHANGE_VIDEO_STABILISATION;
       break;
     case PROP_EXPOSURE_COMPENSATION:
       src->capture_config.camera_parameters.exposureCompensation =
           g_value_get_int (value);
+      src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS;
       break;
     case PROP_EXPOSURE_MODE:
       src->capture_config.camera_parameters.exposureMode =
           g_value_get_enum (value);
+      src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS;
       break;
     case PROP_EXPOSURE_METERING_MODE:
       src->capture_config.camera_parameters.exposureMeterMode =
           g_value_get_enum (value);
+      src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS;
       break;
     case PROP_ROTATION:
       src->capture_config.camera_parameters.rotation = g_value_get_int (value);
       break;
     case PROP_AWB_MODE:
       src->capture_config.camera_parameters.awbMode = g_value_get_enum (value);
+      src->capture_config.change_flags |= PROP_CHANGE_AWB;
       break;
     case PROP_AWB_GAIN_RED:
       src->capture_config.camera_parameters.awb_gains_r =
           g_value_get_float (value);
+      src->capture_config.change_flags |= PROP_CHANGE_AWB;
       break;
     case PROP_AWB_GAIN_BLUE:
       src->capture_config.camera_parameters.awb_gains_b =
           g_value_get_float (value);
+      src->capture_config.change_flags |= PROP_CHANGE_AWB;
       break;
     case PROP_IMAGE_EFFECT:
       src->capture_config.camera_parameters.imageEffect =
           g_value_get_enum (value);
+      src->capture_config.change_flags |= PROP_CHANGE_IMAGE_COLOUR_EFFECT;
       break;
     case PROP_HFLIP:
       src->capture_config.camera_parameters.hflip = g_value_get_boolean (value);
+      src->capture_config.change_flags |= PROP_CHANGE_ORIENTATION;
       break;
     case PROP_VFLIP:
       src->capture_config.camera_parameters.vflip = g_value_get_boolean (value);
+      src->capture_config.change_flags |= PROP_CHANGE_ORIENTATION;
       break;
     case PROP_ROI_X:
       src->capture_config.camera_parameters.roi.x = g_value_get_float (value);
+      src->capture_config.change_flags |= PROP_CHANGE_ROI;
       break;
     case PROP_ROI_Y:
       src->capture_config.camera_parameters.roi.y = g_value_get_float (value);
+      src->capture_config.change_flags |= PROP_CHANGE_ROI;
       break;
     case PROP_ROI_W:
       src->capture_config.camera_parameters.roi.w = g_value_get_float (value);
+      src->capture_config.change_flags |= PROP_CHANGE_ROI;
       break;
     case PROP_ROI_H:
       src->capture_config.camera_parameters.roi.h = g_value_get_float (value);
+      src->capture_config.change_flags |= PROP_CHANGE_ROI;
       break;
     case PROP_QUANTISATION_PARAMETER:
       src->capture_config.quantisationParameter = g_value_get_int (value);
+      src->capture_config.change_flags |= PROP_CHANGE_ENCODING;
       break;
     case PROP_INLINE_HEADERS:
       src->capture_config.bInlineHeaders = g_value_get_boolean (value);
@@ -547,17 +592,21 @@ gst_rpi_cam_src_set_property (GObject * object, guint prop_id,
     case PROP_SHUTTER_SPEED:
       src->capture_config.camera_parameters.shutter_speed =
           g_value_get_int (value);
+      src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS;
       break;
     case PROP_DRC:
       src->capture_config.camera_parameters.drc_level =
           g_value_get_enum (value);
+      src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS;
       break;
     case PROP_SENSOR_MODE:
       src->capture_config.sensor_mode = g_value_get_enum (value);
+      src->capture_config.change_flags |= PROP_CHANGE_SENSOR_SETTINGS;
       break;
     case PROP_ANNOTATION_MODE:
       src->capture_config.camera_parameters.enable_annotate =
           g_value_get_flags (value);
+      src->capture_config.change_flags |= PROP_CHANGE_ANNOTATION;
       break;
     case PROP_ANNOTATION_TEXT:
       strncpy (src->capture_config.camera_parameters.annotate_string,
@@ -565,14 +614,18 @@ gst_rpi_cam_src_set_property (GObject * object, guint prop_id,
       src->capture_config.
           camera_parameters.annotate_string[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V2
           - 1] = '\0';
+      src->capture_config.change_flags |= PROP_CHANGE_ANNOTATION;
       break;
     case PROP_INTRA_REFRESH_TYPE:
       src->capture_config.intra_refresh_type = g_value_get_enum (value);
+      src->capture_config.change_flags |= PROP_CHANGE_ENCODING;
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
   }
+
+  g_mutex_unlock (&src->config_lock);
 }
 
 static void
@@ -580,6 +633,8 @@ gst_rpi_cam_src_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec)
 {
   GstRpiCamSrc *src = GST_RPICAMSRC (object);
+
+  g_mutex_lock (&src->config_lock);
   switch (prop_id) {
     case PROP_CAMERA_NUMBER:
       g_value_set_int (value, src->capture_config.cameraNum);
@@ -704,6 +759,7 @@ gst_rpi_cam_src_get_property (GObject * object, guint prop_id,
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
   }
+  g_mutex_unlock (&src->config_lock);
 }
 
 static gboolean
@@ -711,7 +767,9 @@ gst_rpi_cam_src_start (GstBaseSrc * parent)
 {
   GstRpiCamSrc *src = GST_RPICAMSRC (parent);
   GST_LOG_OBJECT (src, "In src_start()");
+  g_mutex_lock (&src->config_lock);
   src->capture_state = raspi_capture_setup (&src->capture_config);
+  g_mutex_unlock (&src->config_lock);
   if (src->capture_state == NULL)
     return FALSE;
   return TRUE;
@@ -878,6 +936,13 @@ gst_rpi_cam_src_create (GstPushSrc * parent, GstBuffer ** buf)
   base_time = GST_ELEMENT_CAST (src)->base_time;
   GST_OBJECT_UNLOCK (src);
 
+  g_mutex_lock (&src->config_lock);
+  if (src->capture_config.change_flags) {
+    raspi_capture_update_config (src->capture_state, &src->capture_config);
+    src->capture_config.change_flags = 0;
+  }
+  g_mutex_unlock (&src->config_lock);
+
   /* FIXME: Use custom allocator */
   ret = raspi_capture_fill_buffer (src->capture_state, buf, clock, base_time);
   if (*buf)
index 86f5d24..0bfc2b1 100644 (file)
@@ -72,6 +72,8 @@ struct _GstRpiCamSrc
   RASPIVID_CONFIG capture_config;
   RASPIVID_STATE *capture_state;
   gboolean started;
+
+  GMutex config_lock;
 };
 
 struct _GstRpiCamSrcClass