示例#1
0
static void
gst_base_camera_src_set_property (GObject * object,
    guint prop_id, const GValue * value, GParamSpec * pspec)
{
  GstBaseCameraSrc *self = GST_BASE_CAMERA_SRC (object);

  switch (prop_id) {
    case PROP_MODE:
      gst_base_camera_src_set_mode (GST_BASE_CAMERA_SRC (self),
          g_value_get_enum (value));
      break;
    case PROP_ZOOM:{
      self->zoom = g_value_get_float (value);
      /* limit to max-zoom */
      if (self->zoom > self->max_zoom) {
        GST_DEBUG_OBJECT (self, "Clipping zoom %f to max-zoom %f", self->zoom,
            self->max_zoom);
        self->zoom = self->max_zoom;
      }
      /* does not set it if in NULL, the src is not created yet */
      if (GST_STATE (self) != GST_STATE_NULL)
        gst_base_camera_src_setup_zoom (self);
      break;
    }
    case PROP_POST_PREVIEW:
      self->post_preview = g_value_get_boolean (value);
      break;
    case PROP_PREVIEW_CAPS:{
      GstCaps *new_caps = NULL;
      new_caps = (GstCaps *) gst_value_get_caps (value);
      if (!gst_caps_is_equal (self->preview_caps, new_caps)) {
        gst_caps_replace (&self->preview_caps, new_caps);
        gst_base_camera_src_setup_preview (self, new_caps);
      } else {
        GST_DEBUG_OBJECT (self, "New preview caps equal current preview caps");
      }
    }
      break;
    case PROP_PREVIEW_FILTER:
      if (self->preview_filter)
        gst_object_unref (self->preview_filter);
      self->preview_filter = g_value_dup_object (value);
      if (!gst_camerabin_preview_set_filter (self->preview_pipeline,
              self->preview_filter)) {
        GST_WARNING_OBJECT (self,
            "Cannot change preview filter, is element in NULL state?");
      }
      break;
    case PROP_AUTO_START:
      self->auto_start = g_value_get_boolean (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
      break;
  }
}
/**
 * gst_wrapper_camera_bin_src_imgsrc_probe:
 *
 * Buffer probe called before sending each buffer to image queue.
 */
static gboolean
gst_wrapper_camera_bin_src_imgsrc_probe (GstPad * pad, GstBuffer * buffer,
    gpointer data)
{
  GstWrapperCameraBinSrc *self = GST_WRAPPER_CAMERA_BIN_SRC (data);
  GstBaseCameraSrc *camerasrc = GST_BASE_CAMERA_SRC (data);
  gboolean ret = FALSE;

  GST_LOG_OBJECT (self, "Image probe, mode %d, capture count %d",
      camerasrc->mode, self->image_capture_count);

  g_mutex_lock (camerasrc->capturing_mutex);
  if (self->image_capture_count > 0) {
    ret = TRUE;
    self->image_capture_count--;

    /* post preview */
    /* TODO This can likely be optimized if the viewfinder caps is the same as
     * the preview caps, avoiding another scaling of the same buffer. */
    GST_DEBUG_OBJECT (self, "Posting preview for image");
    gst_base_camera_src_post_preview (camerasrc, buffer);

    if (self->image_capture_count == 0) {
      gst_base_camera_src_finish_capture (camerasrc);
    }
  }
  g_mutex_unlock (camerasrc->capturing_mutex);
  return ret;
}
示例#3
0
static GstStateChangeReturn
gst_base_camera_src_change_state (GstElement * element,
    GstStateChange transition)
{
  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
  GstBaseCameraSrc *self = GST_BASE_CAMERA_SRC (element);

  GST_DEBUG_OBJECT (self, "%d -> %d",
      GST_STATE_TRANSITION_CURRENT (transition),
      GST_STATE_TRANSITION_NEXT (transition));

  switch (transition) {
    case GST_STATE_CHANGE_NULL_TO_READY:
      if (!construct_pipeline (self))
        return GST_STATE_CHANGE_FAILURE;
      break;
    case GST_STATE_CHANGE_READY_TO_PAUSED:
      if (!setup_pipeline (self))
        return GST_STATE_CHANGE_FAILURE;
      break;
    default:
      break;
  }

  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);

  return ret;
}
static void
gst_base_camera_src_get_property (GObject * object,
    guint prop_id, GValue * value, GParamSpec * pspec)
{
  GstBaseCameraBinSrc *self = GST_BASE_CAMERA_SRC (object);

  switch (prop_id) {
    case PROP_MODE:
      g_value_set_enum (value, self->mode);
      break;
    case PROP_READY_FOR_CAPTURE:
      g_value_set_boolean (value, !self->capturing);
      break;
    case PROP_ZOOM:
      g_value_set_float (value, self->zoom);
      break;
    case PROP_MAX_ZOOM:
      g_value_set_float (value, self->max_zoom);
      break;
    case PROP_POST_PREVIEW:
      g_value_set_boolean (value, self->post_preview);
      break;
    case PROP_PREVIEW_CAPS:
      if (self->preview_caps)
        gst_value_set_caps (value, self->preview_caps);
      break;
    case PROP_PREVIEW_FILTER:
      if (self->preview_filter)
        g_value_set_object (value, self->preview_filter);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
      break;
  }
}
示例#5
0
static GstStateChangeReturn
gst_base_camera_src_change_state (GstElement * element,
    GstStateChange transition)
{
  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
  GstBaseCameraSrc *self = GST_BASE_CAMERA_SRC (element);

  GST_DEBUG_OBJECT (self, "%d -> %d",
      GST_STATE_TRANSITION_CURRENT (transition),
      GST_STATE_TRANSITION_NEXT (transition));

  switch (transition) {
    case GST_STATE_CHANGE_NULL_TO_READY:
      if (!construct_pipeline (self))
        return GST_STATE_CHANGE_FAILURE;

      if (self->preview_pipeline == NULL) {
        /* failed to create preview pipeline, fail state change */
        return GST_STATE_CHANGE_FAILURE;
      }

      if (self->preview_caps) {
        GST_DEBUG_OBJECT (self,
            "Setting preview pipeline caps %" GST_PTR_FORMAT,
            self->preview_caps);
        gst_camerabin_preview_set_caps (self->preview_pipeline,
            self->preview_caps);
      }
      break;
    case GST_STATE_CHANGE_READY_TO_PAUSED:
      if (!setup_pipeline (self))
        return GST_STATE_CHANGE_FAILURE;
      /* without this the preview pipeline will not post buffer
       * messages on the pipeline */
      gst_element_set_state (self->preview_pipeline->pipeline,
          GST_STATE_PLAYING);
      if (self->auto_start)
        g_signal_emit_by_name (G_OBJECT (self), "start-capture", NULL);
      break;
    default:
      break;
  }

  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);

  switch (transition) {
    case GST_STATE_CHANGE_PAUSED_TO_READY:
      gst_element_set_state (self->preview_pipeline->pipeline, GST_STATE_READY);
      if (self->auto_start)
        g_signal_emit_by_name (G_OBJECT (self), "stop-capture", NULL);
      break;
    case GST_STATE_CHANGE_READY_TO_NULL:
      gst_element_set_state (self->preview_pipeline->pipeline, GST_STATE_NULL);
      break;
    default:
      break;
  }

  return ret;
}
static GstStateChangeReturn
gst_base_camera_src_change_state (GstElement * element,
    GstStateChange transition)
{
  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
  GstBaseCameraBinSrc *self = GST_BASE_CAMERA_SRC (element);

  GST_DEBUG_OBJECT (self, "%d -> %d",
      GST_STATE_TRANSITION_CURRENT (transition),
      GST_STATE_TRANSITION_NEXT (transition));

  switch (transition) {
    case GST_STATE_CHANGE_NULL_TO_READY:
      if (!construct_pipeline (self))
        return GST_STATE_CHANGE_FAILURE;

      /* recreate the preview pipeline */
      if (self->preview_pipeline && self->preview_filter_changed) {
        gst_camerabin_destroy_preview_pipeline (self->preview_pipeline);
        self->preview_pipeline = NULL;
      }

      if (self->preview_pipeline == NULL)
        self->preview_pipeline =
            gst_camerabin_create_preview_pipeline (GST_ELEMENT_CAST (self),
            self->preview_filter);

      g_assert (self->preview_pipeline != NULL);
      self->preview_filter_changed = FALSE;
      if (self->preview_caps) {
        GST_DEBUG_OBJECT (self,
            "Setting preview pipeline caps %" GST_PTR_FORMAT,
            self->preview_caps);
        gst_camerabin_preview_set_caps (self->preview_pipeline,
            self->preview_caps);
      }
      break;
    case GST_STATE_CHANGE_READY_TO_PAUSED:
      if (!setup_pipeline (self))
        return GST_STATE_CHANGE_FAILURE;
      gst_element_set_state (self->preview_pipeline->pipeline,
          GST_STATE_PLAYING);
      break;
    default:
      break;
  }

  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);

  switch (transition) {
    case GST_STATE_CHANGE_READY_TO_NULL:
      gst_element_set_state (self->preview_pipeline->pipeline, GST_STATE_NULL);
      break;
    default:
      break;
  }

  return ret;
}
static gboolean
start_image_capture (GstWrapperCameraBinSrc * self)
{
  GstBaseCameraSrc *bcamsrc = GST_BASE_CAMERA_SRC (self);
  GstPhotography *photography =
      (GstPhotography *) gst_bin_get_by_interface (GST_BIN_CAST (bcamsrc),
      GST_TYPE_PHOTOGRAPHY);
  gboolean ret = FALSE;
  GstCaps *caps;

  GST_DEBUG_OBJECT (self, "Starting image capture");
  gst_element_set_state (self->src_vid_src, GST_STATE_READY);

  if (self->image_renegotiate) {
    /* clean capsfilter caps so they don't interfere here */
    g_object_set (self->src_filter, "caps", NULL, NULL);
    if (self->src_zoom_filter)
      g_object_set (self->src_zoom_filter, "caps", NULL, NULL);

    caps = gst_pad_get_allowed_caps (self->imgsrc);

    gst_caps_replace (&self->image_capture_caps, caps);
    gst_caps_unref (caps);

    /* FIXME - do we need to update basecamerasrc width/height somehow here?
     * if not, i think we need to do something about _when_ they get updated
     * to be sure that set_element_zoom doesn't use the wrong values */

    /* We caught this event in the src pad event handler and now we want to
     * actually push it upstream */
    gst_pad_send_event (self->outsel_imgpad, gst_event_new_reconfigure ());

    self->image_renegotiate = FALSE;
  }

  if (photography) {
    gst_element_set_state (self->src_vid_src, GST_STATE_PLAYING);
    GST_DEBUG_OBJECT (self, "prepare image capture caps %" GST_PTR_FORMAT,
        self->image_capture_caps);
    ret = gst_photography_prepare_for_capture (photography,
        (GstPhotographyCapturePrepared) img_capture_prepared,
        self->image_capture_caps, self);
  } else {
    g_mutex_unlock (&bcamsrc->capturing_mutex);
    gst_wrapper_camera_bin_reset_video_src_caps (self,
        self->image_capture_caps);
    g_mutex_lock (&bcamsrc->capturing_mutex);
    ret = TRUE;
    gst_element_set_state (self->src_vid_src, GST_STATE_PLAYING);
  }

  return ret;
}
示例#8
0
static void
gst_base_camera_src_set_property (GObject * object,
    guint prop_id, const GValue * value, GParamSpec * pspec)
{
  GstBaseCameraSrc *self = GST_BASE_CAMERA_SRC (object);

  switch (prop_id) {
    case PROP_MODE:
      gst_base_camera_src_set_mode (GST_BASE_CAMERA_SRC (self),
          g_value_get_enum (value));
      break;
    case PROP_ZOOM:{
      g_atomic_int_set (&self->zoom, g_value_get_int (value));
      /* does not set it if in NULL, the src is not created yet */
      if (GST_STATE (self) != GST_STATE_NULL)
        gst_base_camera_src_setup_zoom (self);
      break;
    }
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
      break;
  }
}
/**
 * set_capsfilter_caps:
 * @self: camerasrc object
 * @new_caps: pointer to caps object to set
 *
 * Set given caps to camerabin capsfilters.
 */
static void
set_capsfilter_caps (GstWrapperCameraBinSrc * self, GstCaps * new_caps)
{
  GST_INFO_OBJECT (self, "new_caps:%" GST_PTR_FORMAT, new_caps);

  /* Update zoom */
  gst_base_camera_src_setup_zoom (GST_BASE_CAMERA_SRC (self));

  /* Update capsfilters */
  g_object_set (G_OBJECT (self->src_filter), "caps", new_caps, NULL);
  if (self->src_zoom_filter)
    g_object_set (G_OBJECT (self->src_zoom_filter), "caps", new_caps, NULL);
  update_aspect_filter (self, new_caps);
  GST_INFO_OBJECT (self, "updated");
}
static gboolean
set_element_zoom (GstWrapperCameraBinSrc * self, gfloat zoom)
{
  gboolean ret = FALSE;
  GstBaseCameraSrc *bcamsrc = GST_BASE_CAMERA_SRC (self);
  gint w2_crop = 0, h2_crop = 0;
  GstPad *pad_zoom_sink = NULL;
  gint left = self->base_crop_left;
  gint right = self->base_crop_right;
  gint top = self->base_crop_top;
  gint bottom = self->base_crop_bottom;

  if (self->src_zoom_crop) {
    /* Update capsfilters to apply the zoom */
    GST_INFO_OBJECT (self, "zoom: %f, orig size: %dx%d", zoom,
        bcamsrc->width, bcamsrc->height);

    if (zoom != ZOOM_1X) {
      w2_crop = (bcamsrc->width - (gint) (bcamsrc->width * ZOOM_1X / zoom)) / 2;
      h2_crop =
          (bcamsrc->height - (gint) (bcamsrc->height * ZOOM_1X / zoom)) / 2;

      left += w2_crop;
      right += w2_crop;
      top += h2_crop;
      bottom += h2_crop;

      /* force number of pixels cropped from left to be even, to avoid slow code
       * path on videoscale */
      left &= 0xFFFE;
    }

    pad_zoom_sink = gst_element_get_static_pad (self->src_zoom_crop, "sink");

    GST_INFO_OBJECT (self,
        "sw cropping: left:%d, right:%d, top:%d, bottom:%d", left, right, top,
        bottom);

    GST_PAD_STREAM_LOCK (pad_zoom_sink);
    g_object_set (self->src_zoom_crop, "left", left, "right", right, "top",
        top, "bottom", bottom, NULL);
    GST_PAD_STREAM_UNLOCK (pad_zoom_sink);
    gst_object_unref (pad_zoom_sink);
    ret = TRUE;
  }
  return ret;
}
static void
gst_wrapper_camera_bin_src_caps_cb (GObject * gobject, GParamSpec * pspec,
    gpointer user_data)
{
  GstBaseCameraSrc *bcamsrc = GST_BASE_CAMERA_SRC (user_data);
  GstWrapperCameraBinSrc *self = GST_WRAPPER_CAMERA_BIN_SRC (user_data);
  GstPad *src_caps_src_pad;
  GstCaps *caps = NULL;
  GstStructure *in_st = NULL;

  /* get the new caps that were set on the capsfilter that configures the
   * source */
  src_caps_src_pad = gst_element_get_static_pad (self->src_filter, "src");
  caps = gst_pad_query_caps (src_caps_src_pad, NULL);
  gst_object_unref (src_caps_src_pad);
  GST_DEBUG_OBJECT (self, "src-filter caps changed to %s",
      gst_caps_to_string (caps));

  if (gst_caps_get_size (caps)) {
    in_st = gst_caps_get_structure (caps, 0);
    if (in_st) {
      gst_structure_get_int (in_st, "width", &bcamsrc->width);
      gst_structure_get_int (in_st, "height", &bcamsrc->height);

      GST_DEBUG_OBJECT (self, "Source dimensions now: %dx%d", bcamsrc->width,
          bcamsrc->height);
    }
  }

  /* Update zoom */
  gst_base_camera_src_setup_zoom (bcamsrc);

  /* Update post-zoom capsfilter */
  if (self->src_zoom_filter) {
    GstCaps *filtercaps;

    g_object_get (G_OBJECT (self->src_zoom_filter), "caps", &filtercaps, NULL);
    if (!gst_caps_is_equal (filtercaps, caps))
      g_object_set (G_OBJECT (self->src_zoom_filter), "caps", caps, NULL);
    gst_caps_unref (filtercaps);
  }

  /* drop our ref on the caps */
  gst_caps_unref (caps);
};
static void
gst_wrapper_camera_bin_src_caps_cb (GstPad * pad, GParamSpec * pspec,
    gpointer user_data)
{
  GstBaseCameraSrc *bcamsrc = GST_BASE_CAMERA_SRC (user_data);
  GstWrapperCameraBinSrc *self = GST_WRAPPER_CAMERA_BIN_SRC (user_data);
  GstCaps *caps;
  GstStructure *in_st = NULL;

  caps = gst_pad_get_current_caps (pad);

  GST_DEBUG_OBJECT (self, "src-filter caps changed to %" GST_PTR_FORMAT, caps);

  if (caps && gst_caps_get_size (caps)) {
    in_st = gst_caps_get_structure (caps, 0);
    if (in_st) {
      gst_structure_get_int (in_st, "width", &bcamsrc->width);
      gst_structure_get_int (in_st, "height", &bcamsrc->height);

      GST_DEBUG_OBJECT (self, "Source dimensions now: %dx%d", bcamsrc->width,
          bcamsrc->height);
    }
  }

  /* Update zoom */
  gst_base_camera_src_setup_zoom (bcamsrc);

  /* Update post-zoom capsfilter */
  if (self->src_zoom_filter) {
    GstCaps *filtercaps;

    g_object_get (G_OBJECT (self->src_zoom_filter), "caps", &filtercaps, NULL);

    if (caps != filtercaps && (caps == NULL || filtercaps == NULL ||
            !gst_caps_is_equal (filtercaps, caps)))
      g_object_set (G_OBJECT (self->src_zoom_filter), "caps", caps, NULL);

    if (filtercaps)
      gst_caps_unref (filtercaps);
  }

  if (caps)
    gst_caps_unref (caps);
};
示例#13
0
static gboolean
start_image_capture (GstWrapperCameraBinSrc * self)
{
  GstBaseCameraSrc *bcamsrc = GST_BASE_CAMERA_SRC (self);
  GstPhotography *photography = gst_base_camera_src_get_photography (bcamsrc);
  gboolean ret = FALSE;
  GstCaps *caps;

  GST_DEBUG_OBJECT (self, "Starting image capture");

  if (self->image_renegotiate) {
    /* clean capsfilter caps so they don't interfere here */
    g_object_set (self->src_filter, "caps", NULL, NULL);
    if (self->src_zoom_filter)
      g_object_set (self->src_zoom_filter, "caps", NULL, NULL);

    caps = gst_pad_get_allowed_caps (self->imgsrc);

    caps = gst_caps_make_writable (caps);
    gst_pad_fixate_caps (self->imgsrc, caps);

    gst_caps_replace (&self->image_capture_caps, caps);
    gst_caps_unref (caps);

    self->image_renegotiate = FALSE;
  }

  if (photography) {
    GST_DEBUG_OBJECT (self, "prepare image capture caps %" GST_PTR_FORMAT,
        self->image_capture_caps);
    ret = gst_photography_prepare_for_capture (photography,
        (GstPhotoCapturePrepared) img_capture_prepared,
        self->image_capture_caps, self);
  } else {
    g_mutex_unlock (bcamsrc->capturing_mutex);
    gst_wrapper_camera_bin_reset_video_src_caps (self,
        self->image_capture_caps);
    g_mutex_lock (bcamsrc->capturing_mutex);
    ret = TRUE;
  }

  return ret;
}
示例#14
0
static void
gst_base_camera_src_get_property (GObject * object,
    guint prop_id, GValue * value, GParamSpec * pspec)
{
  GstBaseCameraSrc *self = GST_BASE_CAMERA_SRC (object);

  switch (prop_id) {
    case PROP_MODE:
      g_value_set_enum (value, self->mode);
      break;
    case PROP_READY_FOR_CAPTURE:
      g_value_set_boolean (value, !self->capturing);
      break;
    case PROP_ZOOM:
      g_value_set_int (value, g_atomic_int_get (&self->zoom));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (self, prop_id, pspec);
      break;
  }
}
示例#15
0
/**
 * gst_wrapper_camera_bin_src_imgsrc_probe:
 *
 * Buffer probe called before sending each buffer to image queue.
 */
static gboolean
gst_wrapper_camera_bin_src_imgsrc_probe (GstPad * pad, GstBuffer * buffer,
    gpointer data)
{
  GstWrapperCameraBinSrc *self = GST_WRAPPER_CAMERA_BIN_SRC (data);
  GstBaseCameraSrc *camerasrc = GST_BASE_CAMERA_SRC (data);
  gboolean ret = FALSE;

  GST_LOG_OBJECT (self, "Image probe, mode %d, capture count %d",
      camerasrc->mode, self->image_capture_count);

  g_mutex_lock (camerasrc->capturing_mutex);
  if (self->image_capture_count > 0) {
    ret = TRUE;
    self->image_capture_count--;
    if (self->image_capture_count == 0) {
      gst_base_camera_src_finish_capture (camerasrc);
    }
  }
  g_mutex_unlock (camerasrc->capturing_mutex);
  return ret;
}
/**
 * gst_wrapper_camera_bin_src_imgsrc_probe:
 *
 * Buffer probe called before sending each buffer to image queue.
 */
static GstPadProbeReturn
gst_wrapper_camera_bin_src_imgsrc_probe (GstPad * pad, GstPadProbeInfo * info,
    gpointer data)
{
  GstWrapperCameraBinSrc *self = GST_WRAPPER_CAMERA_BIN_SRC (data);
  GstBaseCameraSrc *camerasrc = GST_BASE_CAMERA_SRC (data);
  GstBuffer *buffer = GST_BUFFER (info->data);
  GstPadProbeReturn ret = GST_PAD_PROBE_DROP;

  GST_LOG_OBJECT (self, "Image probe, mode %d, capture count %d bufsize: %"
      G_GSIZE_FORMAT, camerasrc->mode, self->image_capture_count,
      gst_buffer_get_size (buffer));

  g_mutex_lock (&camerasrc->capturing_mutex);
  if (self->image_capture_count > 0) {
    GstSample *sample;
    GstCaps *caps;
    ret = GST_PAD_PROBE_OK;
    self->image_capture_count--;

    /* post preview */
    /* TODO This can likely be optimized if the viewfinder caps is the same as
     * the preview caps, avoiding another scaling of the same buffer. */
    GST_DEBUG_OBJECT (self, "Posting preview for image");
    caps = gst_pad_get_current_caps (pad);
    sample = gst_sample_new (buffer, caps, NULL, NULL);
    gst_base_camera_src_post_preview (camerasrc, sample);
    gst_caps_unref (caps);
    gst_sample_unref (sample);

    if (self->image_capture_count == 0) {
      gst_base_camera_src_finish_capture (camerasrc);
    }
  }
  g_mutex_unlock (&camerasrc->capturing_mutex);
  return ret;
}
/**
 * adapt_image_capture:
 * @self: camerasrc object
 * @in_caps: caps object that describes incoming image format
 *
 * Adjust capsfilters and crop according image capture caps if necessary.
 * The captured image format from video source might be different from
 * what application requested, so we can try to fix that in camerabin.
 *
 */
static void
adapt_image_capture (GstWrapperCameraBinSrc * self, GstCaps * in_caps)
{
  GstBaseCameraSrc *bcamsrc = GST_BASE_CAMERA_SRC (self);
  GstStructure *in_st, *new_st, *req_st;
  gint in_width = 0, in_height = 0, req_width = 0, req_height = 0, crop = 0;
  gdouble ratio_w, ratio_h;
  GstCaps *filter_caps = NULL;

  GST_LOG_OBJECT (self, "in caps: %" GST_PTR_FORMAT, in_caps);
  GST_LOG_OBJECT (self, "requested caps: %" GST_PTR_FORMAT,
      self->image_capture_caps);

  in_st = gst_caps_get_structure (in_caps, 0);
  gst_structure_get_int (in_st, "width", &in_width);
  gst_structure_get_int (in_st, "height", &in_height);

  req_st = gst_caps_get_structure (self->image_capture_caps, 0);
  gst_structure_get_int (req_st, "width", &req_width);
  gst_structure_get_int (req_st, "height", &req_height);

  GST_INFO_OBJECT (self, "we requested %dx%d, and got %dx%d", req_width,
      req_height, in_width, in_height);

  new_st = gst_structure_copy (req_st);
  /* If new fields have been added, we need to copy them */
  gst_structure_foreach (in_st, copy_missing_fields, new_st);

  gst_structure_set (new_st, "width", G_TYPE_INT, in_width, "height",
      G_TYPE_INT, in_height, NULL);

  GST_LOG_OBJECT (self, "new image capture caps: %" GST_PTR_FORMAT, new_st);

  /* Crop if requested aspect ratio differs from incoming frame aspect ratio */
  if (self->src_zoom_crop) {

    ratio_w = (gdouble) in_width / req_width;
    ratio_h = (gdouble) in_height / req_height;

    if (ratio_w < ratio_h) {
      crop = in_height - (req_height * ratio_w);
      self->base_crop_top = crop / 2;
      self->base_crop_bottom = crop / 2;
    } else {
      crop = in_width - (req_width * ratio_h);
      self->base_crop_left = crop / 2;
      self->base_crop_right += crop / 2;
    }

    GST_INFO_OBJECT (self,
        "setting base crop: left:%d, right:%d, top:%d, bottom:%d",
        self->base_crop_left, self->base_crop_right, self->base_crop_top,
        self->base_crop_bottom);
    g_object_set (G_OBJECT (self->src_zoom_crop),
        "top", self->base_crop_top,
        "bottom", self->base_crop_bottom,
        "left", self->base_crop_left, "right", self->base_crop_right, NULL);
  }

  /* Update capsfilters */
  if (self->image_capture_caps) {
    gst_caps_unref (self->image_capture_caps);
  }
  self->image_capture_caps = gst_caps_new_full (new_st, NULL);
  set_capsfilter_caps (self, self->image_capture_caps);

  /* Adjust the capsfilter before crop and videoscale elements if necessary */
  if (in_width == bcamsrc->width && in_height == bcamsrc->height) {
    GST_DEBUG_OBJECT (self, "no adaptation with resolution needed");
  } else {
    GST_DEBUG_OBJECT (self,
        "changing %" GST_PTR_FORMAT " from %dx%d to %dx%d", self->src_filter,
        bcamsrc->width, bcamsrc->height, in_width, in_height);
    /* Apply the width and height to filter caps */
    g_object_get (G_OBJECT (self->src_filter), "caps", &filter_caps, NULL);
    filter_caps = gst_caps_make_writable (filter_caps);
    gst_caps_set_simple (filter_caps, "width", G_TYPE_INT, in_width, "height",
        G_TYPE_INT, in_height, NULL);
    g_object_set (G_OBJECT (self->src_filter), "caps", filter_caps, NULL);
    gst_caps_unref (filter_caps);
  }
}
static gboolean
start_image_capture (GstWrapperCameraBinSrc * self)
{
  GstBaseCameraSrc *bcamsrc = GST_BASE_CAMERA_SRC (self);
  GstPhotography *photography =
      (GstPhotography *) gst_bin_get_by_interface (GST_BIN_CAST (bcamsrc),
      GST_TYPE_PHOTOGRAPHY);
  gboolean ret = FALSE;
  GstCaps *caps;
  GstPad *pad, *peer;

  GST_DEBUG_OBJECT (self, "Starting image capture");
  gst_element_set_state (self->src_vid_src, GST_STATE_READY);

  /* FIXME - V4L2 source will not close the device until all buffers have came
   * back. Flushing the pipeline, will ensure it's properly closed, and that
   * setting it back to PLAYING will work. This is more a workaround then a
   * solution to buffer reclaiming. */
  pad = gst_element_get_static_pad (self->src_vid_src, "src");
  peer = gst_pad_get_peer (pad);
  gst_object_unref (pad);
  gst_pad_send_event (peer, gst_event_new_flush_start ());
  gst_pad_send_event (peer, gst_event_new_flush_stop (TRUE));
  gst_object_unref (peer);

  if (self->image_renegotiate) {
    /* clean capsfilter caps so they don't interfere here */
    g_object_set (self->src_filter, "caps", NULL, NULL);
    if (self->src_zoom_filter)
      g_object_set (self->src_zoom_filter, "caps", NULL, NULL);

    caps = gst_pad_get_allowed_caps (self->imgsrc);

    gst_caps_replace (&self->image_capture_caps, caps);
    gst_caps_unref (caps);

    /* FIXME - do we need to update basecamerasrc width/height somehow here?
     * if not, i think we need to do something about _when_ they get updated
     * to be sure that set_element_zoom doesn't use the wrong values */

    /* We caught this event in the src pad event handler and now we want to
     * actually push it upstream */
    gst_pad_send_event (self->outsel_imgpad, gst_event_new_reconfigure ());

    self->image_renegotiate = FALSE;
  }

  if (photography) {
    gst_element_set_state (self->src_vid_src, GST_STATE_PLAYING);
    GST_DEBUG_OBJECT (self, "prepare image capture caps %" GST_PTR_FORMAT,
        self->image_capture_caps);
    ret = gst_photography_prepare_for_capture (photography,
        (GstPhotographyCapturePrepared) img_capture_prepared,
        self->image_capture_caps, self);
  } else {
    g_mutex_unlock (&bcamsrc->capturing_mutex);
    gst_wrapper_camera_bin_reset_video_src_caps (self,
        self->image_capture_caps);
    g_mutex_lock (&bcamsrc->capturing_mutex);
    ret = TRUE;
    gst_element_set_state (self->src_vid_src, GST_STATE_PLAYING);
  }

  return ret;
}