Example #1
0
static void
gst_v4lsrc_set_property (GObject * object,
                         guint prop_id, const GValue * value, GParamSpec * pspec)
{
    GstV4lSrc *v4lsrc = GST_V4LSRC (object);

    switch (prop_id) {
    case PROP_AUTOPROBE:
        g_return_if_fail (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc)));
        v4lsrc->autoprobe = g_value_get_boolean (value);
        break;
    case PROP_AUTOPROBE_FPS:
        g_return_if_fail (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc)));
        v4lsrc->autoprobe_fps = g_value_get_boolean (value);
        break;
    case PROP_COPY_MODE:
        v4lsrc->copy_mode = g_value_get_boolean (value);
        break;
    case PROP_TIMESTAMP_OFFSET:
        v4lsrc->timestamp_offset = g_value_get_int64 (value);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
    }
}
Example #2
0
static gboolean
gst_v4lsrc_stop (GstBaseSrc * src)
{
    GstV4lSrc *v4lsrc = GST_V4LSRC (src);

    if (GST_V4L_IS_ACTIVE (v4lsrc) && !gst_v4lsrc_capture_stop (v4lsrc))
        return FALSE;

    if (GST_V4LELEMENT (v4lsrc)->buffer != NULL) {
        if (!gst_v4lsrc_capture_deinit (v4lsrc))
            return FALSE;
    }

    if (!GST_BASE_SRC_CLASS (parent_class)->stop (src))
        return FALSE;

    g_list_free (v4lsrc->colorspaces);
    v4lsrc->colorspaces = NULL;

    if (v4lsrc->fps_list) {
        g_value_unset (v4lsrc->fps_list);
        g_free (v4lsrc->fps_list);
        v4lsrc->fps_list = NULL;
    }

    return TRUE;
}
Example #3
0
/* start and stop are not symmetric -- start will open the device, but not start
   capture. it's setcaps that will start capture, which is called via basesrc's
   negotiate method. stop will both stop capture and close the device.
 */
static gboolean
gst_v4lsrc_start (GstBaseSrc * src)
{
  GstV4lSrc *v4lsrc = GST_V4LSRC (src);

  v4lsrc->offset = 0;

  return TRUE;
}
Example #4
0
/* start and stop are not symmetric -- start will open the device, but not start
   capture. it's setcaps that will start capture, which is called via basesrc's
   negotiate method. stop will both stop capture and close the device.
 */
static gboolean
gst_v4lsrc_start (GstBaseSrc * src)
{
    GstV4lSrc *v4lsrc = GST_V4LSRC (src);

    if (!GST_BASE_SRC_CLASS (parent_class)->start (src))
        return FALSE;

    v4lsrc->offset = 0;

    return TRUE;
}
static GstData *
gst_v4ljpegsrc_get (GstPad * pad)
{
  GstV4lJpegSrc *v4ljpegsrc;
  GstV4lSrc *v4lsrc;
  GstData *data;
  GstBuffer *buf;
  GstBuffer *outbuf;
  int jpeg_size;

  g_return_val_if_fail (pad != NULL, NULL);
  v4ljpegsrc = GST_V4LJPEGSRC (gst_pad_get_parent (pad));
  v4lsrc = GST_V4LSRC (v4ljpegsrc);

  /* Fetch from the v4lsrc class get fn.  */
  data = v4ljpegsrc->getfn (pad);

  /* If not a buffer, return it unchanged */
  if (!data || (!GST_IS_BUFFER (data)))
    return data;

  buf = GST_BUFFER (data);

  /* Confirm that the buffer contains jpeg data */

  /* 
   * Create a new subbuffer from the jpeg data 
   * The first 2 bytes in the buffer are the size of the jpeg data
   */
  if (GST_BUFFER_SIZE (buf) > 2) {
    jpeg_size = (int) (GST_READ_UINT16_LE (GST_BUFFER_DATA (buf))) * 8;
  } else
    jpeg_size = 0;

  /* Check that the size is sensible */
  if ((jpeg_size <= 0) || (jpeg_size > GST_BUFFER_SIZE (buf) - 2)) {
    GST_ELEMENT_ERROR (v4ljpegsrc, STREAM, FORMAT, (NULL),
        ("Invalid non-jpeg frame from camera"));
    return NULL;
  }

  GST_DEBUG_OBJECT (v4ljpegsrc, "Creating JPEG subbuffer of size %d",
      jpeg_size);
  outbuf = gst_buffer_create_sub (buf, 2, jpeg_size);

  /* Copy timestamps onto the subbuffer */
  gst_buffer_stamp (outbuf, buf);

  /* Release the main buffer */
  gst_buffer_unref (buf);

  return GST_DATA (outbuf);
}
Example #6
0
/* this function is a bit of a last resort */
static void
gst_v4lsrc_fixate (GstBaseSrc * bsrc, GstCaps * caps)
{
    GstStructure *structure;
    int i;
    int targetwidth, targetheight;
    GstV4lSrc *v4lsrc = GST_V4LSRC (bsrc);
    struct video_capability *vcap = &GST_V4LELEMENT (v4lsrc)->vcap;
    struct video_window *vwin = &GST_V4LELEMENT (v4lsrc)->vwin;

    if (GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) {
        GST_DEBUG_OBJECT (v4lsrc, "device reported w: %d-%d, h: %d-%d",
                          vcap->minwidth, vcap->maxwidth, vcap->minheight, vcap->maxheight);
        targetwidth = vcap->minwidth;
        targetheight = vcap->minheight;
        /* if we can get the current vwin settings, we use those to fixate */
        if (!gst_v4l_get_capabilities (GST_V4LELEMENT (v4lsrc)))
            GST_DEBUG_OBJECT (v4lsrc, "failed getting capabilities");
        else {
            targetwidth = vwin->width;
            targetheight = vwin->height;
        }
    } else {
        GST_DEBUG_OBJECT (v4lsrc, "device closed, guessing");
        targetwidth = 320;
        targetheight = 200;
    }

    GST_DEBUG_OBJECT (v4lsrc, "targetting %dx%d", targetwidth, targetheight);

    for (i = 0; i < gst_caps_get_size (caps); ++i) {
        const GValue *v;

        structure = gst_caps_get_structure (caps, i);
        gst_structure_fixate_field_nearest_int (structure, "width", targetwidth);
        gst_structure_fixate_field_nearest_int (structure, "height", targetheight);
        gst_structure_fixate_field_nearest_fraction (structure, "framerate", 15, 2);

        v = gst_structure_get_value (structure, "format");
        if (v && G_VALUE_TYPE (v) != GST_TYPE_FOURCC) {
            guint32 fourcc;

            g_return_if_fail (G_VALUE_TYPE (v) == GST_TYPE_LIST);

            fourcc = gst_value_get_fourcc (gst_value_list_get_value (v, 0));
            gst_structure_set (structure, "format", GST_TYPE_FOURCC, fourcc, NULL);
        }
    }
}
static void
gst_v4ljpegsrc_init (GstV4lJpegSrc * v4ljpegsrc)
{
  GstV4lSrc *v4lsrc = GST_V4LSRC (v4ljpegsrc);
  GstPad *pad = v4lsrc->srcpad;

  /*
   * Stash away and then replace the getcaps and get functions on the src pad
   */
  v4ljpegsrc->getfn = GST_RPAD_GETFUNC (pad);
  v4ljpegsrc->getcapsfn = GST_RPAD_GETCAPSFUNC (pad);

  gst_pad_set_get_function (v4lsrc->srcpad, gst_v4ljpegsrc_get);
  gst_pad_set_getcaps_function (v4lsrc->srcpad, gst_v4ljpegsrc_getcaps);
  gst_pad_set_link_function (v4lsrc->srcpad, gst_v4ljpegsrc_src_link);
}
Example #8
0
static gboolean
gst_v4lsrc_query (GstBaseSrc * bsrc, GstQuery * query)
{
    GstV4lSrc *v4lsrc;
    gboolean res = FALSE;

    v4lsrc = GST_V4LSRC (bsrc);

    switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_LATENCY:
    {
        GstClockTime min_latency, max_latency;
        gint fps_n, fps_d;

        /* device must be open */
        if (!GST_V4L_IS_OPEN (v4lsrc))
            goto done;

        /* we must have a framerate */
        if (!(res = gst_v4lsrc_get_fps (v4lsrc, &fps_n, &fps_d)))
            goto done;

        /* min latency is the time to capture one frame */
        min_latency = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);

        /* max latency is total duration of the frame buffer */
        max_latency = v4lsrc->mbuf.frames * min_latency;

        GST_DEBUG_OBJECT (bsrc,
                          "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
                          GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));

        /* we are always live, the min latency is 1 frame and the max latency is
         * the complete buffer of frames. */
        gst_query_set_latency (query, TRUE, min_latency, max_latency);

        res = TRUE;
        break;
    }
    default:
        res = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
        break;
    }
done:
    return res;
}
static GstCaps *
gst_v4ljpegsrc_getcaps (GstPad * pad)
{
  GstCaps *list;
  GstV4lJpegSrc *v4ljpegsrc = GST_V4LJPEGSRC (gst_pad_get_parent (pad));
  GstV4lSrc *v4lsrc = GST_V4LSRC (v4ljpegsrc);
  struct video_capability *vcap = &GST_V4LELEMENT (v4lsrc)->vcap;
  gfloat fps = 0.0;

  if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) {
    return gst_caps_new_any ();
  }
  if (!v4lsrc->autoprobe) {
    /* FIXME: query current caps and return those, with _any appended */
    return gst_caps_new_any ();
  }

  list = gst_caps_new_simple ("image/jpeg", NULL);
  GST_DEBUG_OBJECT (v4ljpegsrc,
      "Device reports w: %d-%d, h: %d-%d, fps: %f",
      vcap->minwidth, vcap->maxwidth, vcap->minheight, vcap->maxheight, fps);

  if (vcap->minwidth < vcap->maxwidth) {
    gst_caps_set_simple (list, "width", GST_TYPE_INT_RANGE, vcap->minwidth,
        vcap->maxwidth, NULL);
  } else {
    gst_caps_set_simple (list, "width", G_TYPE_INT, vcap->minwidth, NULL);
  }
  if (vcap->minheight < vcap->maxheight) {
    gst_caps_set_simple (list, "height", GST_TYPE_INT_RANGE, vcap->minheight,
        vcap->maxheight, NULL);
  } else {
    gst_caps_set_simple (list, "height", G_TYPE_INT, vcap->minheight, NULL);
  }

  if (v4lsrc->fps_list) {
    GstStructure *structure = gst_caps_get_structure (list, 0);

    gst_structure_set_value (structure, "framerate", v4lsrc->fps_list);
  }
  GST_DEBUG_OBJECT (v4ljpegsrc, "caps: %" GST_PTR_FORMAT, list);

  return list;
}
Example #10
0
static GstFlowReturn
gst_v4lsrc_create (GstPushSrc * src, GstBuffer ** buf)
{
    GstV4lSrc *v4lsrc;
    gint num;

    v4lsrc = GST_V4LSRC (src);

    /* grab a frame from the device */
    if (!gst_v4lsrc_grab_frame (v4lsrc, &num))
        return GST_FLOW_ERROR;

    *buf = gst_v4lsrc_buffer_new (v4lsrc, num);

    if (v4lsrc->copy_mode) {
        GstBuffer *copy = gst_buffer_copy (*buf);

        gst_buffer_unref (*buf);
        *buf = copy;
    }

    return GST_FLOW_OK;
}
Example #11
0
static void
gst_v4lsrc_get_property (GObject * object,
                         guint prop_id, GValue * value, GParamSpec * pspec)
{
    GstV4lSrc *v4lsrc = GST_V4LSRC (object);

    switch (prop_id) {
    case PROP_AUTOPROBE:
        g_value_set_boolean (value, v4lsrc->autoprobe);
        break;
    case PROP_AUTOPROBE_FPS:
        g_value_set_boolean (value, v4lsrc->autoprobe_fps);
        break;
    case PROP_COPY_MODE:
        g_value_set_boolean (value, v4lsrc->copy_mode);
        break;
    case PROP_TIMESTAMP_OFFSET:
        g_value_set_int64 (value, v4lsrc->timestamp_offset);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
        break;
    }
}
Example #12
0
static gboolean
gst_v4lsrc_set_caps (GstBaseSrc * src, GstCaps * caps)
{
    GstV4lSrc *v4lsrc;
    guint32 fourcc;
    gint bpp, depth, w, h, palette = -1;
    const GValue *new_fps;
    gint cur_fps_n, cur_fps_d;
    GstStructure *structure;
    struct video_window *vwin;

    v4lsrc = GST_V4LSRC (src);
    vwin = &GST_V4LELEMENT (v4lsrc)->vwin;

    /* if we're not open, punt -- we'll get setcaps'd later via negotiate */
    if (!GST_V4L_IS_OPEN (v4lsrc))
        return FALSE;

    /* make sure we stop capturing and dealloc buffers */
    if (GST_V4L_IS_ACTIVE (v4lsrc)) {
        if (!gst_v4lsrc_capture_stop (v4lsrc))
            return FALSE;
        if (!gst_v4lsrc_capture_deinit (v4lsrc))
            return FALSE;
    }

    /* it's fixed, one struct */
    structure = gst_caps_get_structure (caps, 0);

    if (strcmp (gst_structure_get_name (structure), "video/x-raw-yuv") == 0)
        gst_structure_get_fourcc (structure, "format", &fourcc);
    else
        fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', ' ');

    gst_structure_get_int (structure, "width", &w);
    gst_structure_get_int (structure, "height", &h);
    new_fps = gst_structure_get_value (structure, "framerate");

    /* set framerate if it's not already correct */
    if (!gst_v4lsrc_get_fps (v4lsrc, &cur_fps_n, &cur_fps_d))
        return FALSE;

    if (new_fps) {
        GST_DEBUG_OBJECT (v4lsrc, "linking with %dx%d at %d/%d fps", w, h,
                          gst_value_get_fraction_numerator (new_fps),
                          gst_value_get_fraction_denominator (new_fps));

        if (gst_value_get_fraction_numerator (new_fps) != cur_fps_n ||
                gst_value_get_fraction_denominator (new_fps) != cur_fps_d) {
            int fps_index = (gst_value_get_fraction_numerator (new_fps) * 16) /
                            (gst_value_get_fraction_denominator (new_fps) * 15);

            GST_DEBUG_OBJECT (v4lsrc, "Trying to set fps index %d", fps_index);
            /* set bits 16 to 21 to 0 */
            vwin->flags &= (0x3F00 - 1);
            /* set bits 16 to 21 to the index */
            vwin->flags |= fps_index << 16;
            if (!gst_v4l_set_window_properties (GST_V4LELEMENT (v4lsrc))) {
                return FALSE;
            }
        }
    }

    switch (fourcc) {
    case GST_MAKE_FOURCC ('I', '4', '2', '0'):
        palette = VIDEO_PALETTE_YUV420P;
        v4lsrc->buffer_size = ((w + 1) & ~1) * ((h + 1) & ~1) * 1.5;
        break;
    case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
        palette = VIDEO_PALETTE_YUV422;
        v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2;
        break;
    case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
        palette = VIDEO_PALETTE_UYVY;
        v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2;
        break;
    case GST_MAKE_FOURCC ('Y', '4', '1', 'B'):
        palette = VIDEO_PALETTE_YUV411P;
        v4lsrc->buffer_size = ((w + 3) & ~3) * h * 1.5;
        break;
    case GST_MAKE_FOURCC ('Y', '4', '1', 'P'):
        palette = VIDEO_PALETTE_YUV411;
        v4lsrc->buffer_size = ((w + 3) & ~3) * h * 1.5;
        break;
    case GST_MAKE_FOURCC ('Y', 'U', 'V', '9'):
        palette = VIDEO_PALETTE_YUV410P;
        v4lsrc->buffer_size = ((w + 3) & ~3) * ((h + 3) & ~3) * 1.125;
        break;
    case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
        palette = VIDEO_PALETTE_YUV422P;
        v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2;
        break;
    case GST_MAKE_FOURCC ('R', 'G', 'B', ' '):
        gst_structure_get_int (structure, "depth", &depth);
        switch (depth) {
        case 15:
            palette = VIDEO_PALETTE_RGB555;
            v4lsrc->buffer_size = w * h * 2;
            break;
        case 16:
            palette = VIDEO_PALETTE_RGB565;
            v4lsrc->buffer_size = w * h * 2;
            break;
        case 24:
            gst_structure_get_int (structure, "bpp", &bpp);
            switch (bpp) {
            case 24:
                palette = VIDEO_PALETTE_RGB24;
                v4lsrc->buffer_size = w * h * 3;
                break;
            case 32:
                palette = VIDEO_PALETTE_RGB32;
                v4lsrc->buffer_size = w * h * 4;
                break;
            default:
                break;
            }
            break;
        default:
            break;
        }
        break;
    default:
        break;
    }

    if (palette == -1) {
        GST_WARNING_OBJECT (v4lsrc, "palette for fourcc %" GST_FOURCC_FORMAT
                            " is -1, refusing link", GST_FOURCC_ARGS (fourcc));
        return FALSE;
    }

    GST_DEBUG_OBJECT (v4lsrc, "trying to set_capture %dx%d, palette %d",
                      w, h, palette);
    /* this only fills in v4lsrc->mmap values */
    if (!gst_v4lsrc_set_capture (v4lsrc, w, h, palette)) {
        GST_WARNING_OBJECT (v4lsrc, "could not set_capture %dx%d, palette %d",
                            w, h, palette);
        return FALSE;
    }

    /* first try the negotiated settings using try_capture */
    if (!gst_v4lsrc_try_capture (v4lsrc, w, h, palette)) {
        GST_DEBUG_OBJECT (v4lsrc, "failed trying palette %d for %dx%d", palette,
                          w, h);
        return FALSE;
    }

    if (!gst_v4lsrc_capture_init (v4lsrc))
        return FALSE;

    if (!gst_v4lsrc_capture_start (v4lsrc))
        return FALSE;

    return TRUE;
}
Example #13
0
static GstCaps *
gst_v4lsrc_get_caps (GstBaseSrc * src)
{
    GstCaps *list;
    GstV4lSrc *v4lsrc = GST_V4LSRC (src);
    struct video_capability *vcap = &GST_V4LELEMENT (v4lsrc)->vcap;
    gint width = GST_V4LELEMENT (src)->vcap.minwidth;
    gint height = GST_V4LELEMENT (src)->vcap.minheight;
    gint i;
    gint fps_n, fps_d;
    GList *item;

    if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) {
        return gst_v4lsrc_get_any_caps ();
    }

    if (!v4lsrc->autoprobe) {
        /* FIXME: query current caps and return those, with _any appended */
        return gst_v4lsrc_get_any_caps ();
    }

    if (!v4lsrc->colorspaces) {
        GST_DEBUG_OBJECT (v4lsrc, "Checking supported palettes");
        for (i = 0; all_palettes[i] != -1; i++) {
            /* try palette out */
            if (!gst_v4lsrc_try_capture (v4lsrc, width, height, all_palettes[i]))
                continue;
            GST_DEBUG_OBJECT (v4lsrc, "Added palette %d (%s) to supported list",
                              all_palettes[i], gst_v4lsrc_palette_name (all_palettes[i]));
            v4lsrc->colorspaces = g_list_append (v4lsrc->colorspaces,
                                                 GINT_TO_POINTER (all_palettes[i]));
        }
        GST_DEBUG_OBJECT (v4lsrc, "%d palette(s) supported",
                          g_list_length (v4lsrc->colorspaces));
        if (v4lsrc->autoprobe_fps) {
            GST_DEBUG_OBJECT (v4lsrc, "autoprobing framerates");
            v4lsrc->fps_list = gst_v4lsrc_get_fps_list (v4lsrc);
        }
    }


    if (!gst_v4lsrc_get_fps (v4lsrc, &fps_n, &fps_d)) {
        fps_n = 0;
        fps_d = 1;
    }

    list = gst_caps_new_empty ();
    for (item = v4lsrc->colorspaces; item != NULL; item = item->next) {
        GstCaps *one;

        one = gst_v4lsrc_palette_to_caps (GPOINTER_TO_INT (item->data));
        if (!one) {
            GST_WARNING_OBJECT (v4lsrc, "Palette %d gave no caps\n",
                                GPOINTER_TO_INT (item->data));
            continue;
        }

        GST_DEBUG_OBJECT (v4lsrc,
                          "Device reports w: %d-%d, h: %d-%d, fps: %d/%d for palette %d",
                          vcap->minwidth, vcap->maxwidth, vcap->minheight, vcap->maxheight,
                          fps_n, fps_d, GPOINTER_TO_INT (item->data));

        if (vcap->minwidth < vcap->maxwidth) {
            gst_caps_set_simple (one, "width", GST_TYPE_INT_RANGE, vcap->minwidth,
                                 vcap->maxwidth, NULL);
        } else {
            gst_caps_set_simple (one, "width", G_TYPE_INT, vcap->minwidth, NULL);
        }
        if (vcap->minheight < vcap->maxheight) {
            gst_caps_set_simple (one, "height", GST_TYPE_INT_RANGE, vcap->minheight,
                                 vcap->maxheight, NULL);
        } else {
            gst_caps_set_simple (one, "height", G_TYPE_INT, vcap->minheight, NULL);
        }

        if (v4lsrc->autoprobe_fps) {
            GstStructure *structure = gst_caps_get_structure (one, 0);

            if (v4lsrc->fps_list) {
                gst_structure_set_value (structure, "framerate", v4lsrc->fps_list);
            } else {
                gst_structure_set (structure, "framerate", GST_TYPE_FRACTION,
                                   fps_n, fps_d, NULL);
            }
        } else {
            gst_caps_set_simple (one, "framerate", GST_TYPE_FRACTION_RANGE,
                                 1, 1, 100, 1, NULL);
        }

        GST_DEBUG_OBJECT (v4lsrc, "caps: %" GST_PTR_FORMAT, one);
        gst_caps_append (list, one);
    }

    return list;
}
static GstPadLinkReturn
gst_v4ljpegsrc_src_link (GstPad * pad, const GstCaps * vscapslist)
{
  GstV4lJpegSrc *v4ljpegsrc;
  GstV4lSrc *v4lsrc;
  gint w, h, palette = -1;
  const GValue *fps;
  GstStructure *structure;
  gboolean was_capturing;
  struct video_window *vwin;

  v4ljpegsrc = GST_V4LJPEGSRC (gst_pad_get_parent (pad));
  v4lsrc = GST_V4LSRC (v4ljpegsrc);
  vwin = &GST_V4LELEMENT (v4lsrc)->vwin;
  was_capturing = v4lsrc->is_capturing;

  /* in case the buffers are active (which means that we already
   * did capsnego before and didn't clean up), clean up anyways */
  if (GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc))) {
    if (was_capturing) {
      if (!gst_v4lsrc_capture_stop (v4lsrc))
        return GST_PAD_LINK_REFUSED;
    }
    if (!gst_v4lsrc_capture_deinit (v4lsrc))
      return GST_PAD_LINK_REFUSED;
  } else if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) {
    return GST_PAD_LINK_DELAYED;
  }

  structure = gst_caps_get_structure (vscapslist, 0);

  gst_structure_get_int (structure, "width", &w);
  gst_structure_get_int (structure, "height", &h);
  fps = gst_structure_get_value (structure, "framerate");

  GST_DEBUG_OBJECT (v4ljpegsrc, "linking with %dx%d at %d/%d fps", w, h,
      gst_value_get_fraction_numerator (fps),
      gst_value_get_fraction_denominator (fps));

  /* set framerate if it's not already correct */
  if (fps != gst_v4lsrc_get_fps (v4lsrc)) {
    int fps_index = fps / 15.0 * 16;

    GST_DEBUG_OBJECT (v4ljpegsrc, "Trying to set fps index %d", fps_index);
    /* set bits 16 to 21 to 0 */
    vwin->flags &= (0x3F00 - 1);
    /* set bits 16 to 21 to the index */
    vwin->flags |= fps_index << 16;
    if (!gst_v4l_set_window_properties (GST_V4LELEMENT (v4lsrc))) {
      return GST_PAD_LINK_DELAYED;
    }
  }

  /*
   * Try to set the camera to capture RGB24 
   */
  palette = VIDEO_PALETTE_RGB24;
  v4lsrc->buffer_size = w * h * 3;

  GST_DEBUG_OBJECT (v4ljpegsrc, "trying to set_capture %dx%d, palette %d",
      w, h, palette);
  /* this only fills in v4lsrc->mmap values */
  if (!gst_v4lsrc_set_capture (v4lsrc, w, h, palette)) {
    GST_WARNING_OBJECT (v4ljpegsrc, "could not set_capture %dx%d, palette %d",
        w, h, palette);
    return GST_PAD_LINK_REFUSED;
  }

  /* first try the negotiated settings using try_capture */
  if (!gst_v4lsrc_try_capture (v4lsrc, w, h, palette)) {
    GST_DEBUG_OBJECT (v4ljpegsrc, "failed trying palette %d for %dx%d", palette,
        w, h);
    return GST_PAD_LINK_REFUSED;
  }

  if (!gst_v4lsrc_capture_init (v4lsrc))
    return GST_PAD_LINK_REFUSED;

  if (was_capturing || GST_STATE (v4lsrc) == GST_STATE_PLAYING) {
    if (!gst_v4lsrc_capture_start (v4lsrc))
      return GST_PAD_LINK_REFUSED;
  }

  return GST_PAD_LINK_OK;
}