static void gst_v4l_xoverlay_set_window_handle (GstXOverlay * overlay, guintptr id) { XID xwindow_id = id; GstV4lElement *v4lelement = GST_V4LELEMENT (overlay); GstV4lXv *v4lxv; XWindowAttributes attr; gboolean change = (v4lelement->xwindow_id != xwindow_id); GST_LOG_OBJECT (v4lelement, "Changing port to %lx", xwindow_id); if (!v4lelement->xv && GST_V4L_IS_OPEN (v4lelement)) gst_v4l_xoverlay_open (v4lelement); v4lxv = v4lelement->xv; if (v4lxv) g_mutex_lock (v4lxv->mutex); if (change) { if (v4lelement->xwindow_id && v4lxv) { GST_DEBUG_OBJECT (v4lelement, "Disabling port %lx", v4lelement->xwindow_id); XvSelectPortNotify (v4lxv->dpy, v4lxv->port, 0); XvSelectVideoNotify (v4lxv->dpy, v4lelement->xwindow_id, 0); XvStopVideo (v4lxv->dpy, v4lxv->port, v4lelement->xwindow_id); } v4lelement->xwindow_id = xwindow_id; } if (!v4lxv || xwindow_id == 0) { if (v4lxv) g_mutex_unlock (v4lxv->mutex); return; } if (change) { GST_DEBUG_OBJECT (v4lelement, "Enabling port %lx", xwindow_id); /* draw */ XvSelectPortNotify (v4lxv->dpy, v4lxv->port, 1); XvSelectVideoNotify (v4lxv->dpy, v4lelement->xwindow_id, 1); } XGetWindowAttributes (v4lxv->dpy, v4lelement->xwindow_id, &attr); XvPutVideo (v4lxv->dpy, v4lxv->port, v4lelement->xwindow_id, DefaultGC (v4lxv->dpy, DefaultScreen (v4lxv->dpy)), 0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height); if (v4lxv->idle_id) g_source_remove (v4lxv->idle_id); v4lxv->idle_id = g_idle_add (idle_refresh, v4lelement); g_mutex_unlock (v4lxv->mutex); }
static void gst_v4l_tuner_set_norm (GstTuner * tuner, GstTunerNorm * norm) { GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); GstV4lTunerNorm *v4lnorm = GST_V4L_TUNER_NORM (norm); gint channel; /* assert that we're opened and that we're using a known item */ g_return_if_fail (GST_V4L_IS_OPEN (v4lelement)); g_return_if_fail (gst_v4l_tuner_contains_norm (v4lelement, v4lnorm)); gst_v4l_get_chan_norm (v4lelement, &channel, NULL); gst_v4l_set_chan_norm (v4lelement, channel, v4lnorm->index); }
static void gst_v4l_tuner_set_channel (GstTuner * tuner, GstTunerChannel * channel) { GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); GstV4lTunerChannel *v4lchannel = GST_V4L_TUNER_CHANNEL (channel); gint norm; /* assert that we're opened and that we're using a known item */ g_return_if_fail (GST_V4L_IS_OPEN (v4lelement)); g_return_if_fail (gst_v4l_tuner_contains_channel (v4lelement, v4lchannel)); gst_v4l_get_chan_norm (v4lelement, NULL, &norm); gst_v4l_set_chan_norm (v4lelement, v4lchannel->index, norm); }
/* 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 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; }
static void gst_v4l_tuner_set_frequency (GstTuner * tuner, GstTunerChannel * channel, gulong frequency) { GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); GstV4lTunerChannel *v4lchannel = GST_V4L_TUNER_CHANNEL (channel); gint chan; /* assert that we're opened and that we're using a known item */ g_return_if_fail (GST_V4L_IS_OPEN (v4lelement)); g_return_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)); g_return_if_fail (gst_v4l_tuner_contains_channel (v4lelement, v4lchannel)); gst_v4l_get_chan_norm (v4lelement, &chan, NULL); if (chan == GST_V4L_TUNER_CHANNEL (channel)->index) { gst_v4l_set_frequency (v4lelement, v4lchannel->tuner, frequency); } }
static GstTunerNorm * gst_v4l_tuner_get_norm (GstTuner * tuner) { GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); GList *item; gint norm; /* assert that we're opened */ g_return_val_if_fail (GST_V4L_IS_OPEN (v4lelement), NULL); gst_v4l_get_chan_norm (v4lelement, NULL, &norm); for (item = v4lelement->norms; item != NULL; item = item->next) { if (norm == GST_V4L_TUNER_NORM (item->data)->index) return GST_TUNER_NORM (item->data); } return NULL; }
static GstTunerChannel * gst_v4l_tuner_get_channel (GstTuner * tuner) { GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); GList *item; gint channel; /* assert that we're opened */ g_return_val_if_fail (GST_V4L_IS_OPEN (v4lelement), NULL); gst_v4l_get_chan_norm (v4lelement, &channel, NULL); for (item = v4lelement->channels; item != NULL; item = item->next) { if (channel == GST_V4L_TUNER_CHANNEL (item->data)->index) return GST_TUNER_CHANNEL (item->data); } return NULL; }
static gint gst_v4l_tuner_signal_strength (GstTuner * tuner, GstTunerChannel * channel) { GstV4lElement *v4lelement = GST_V4LELEMENT (tuner); GstV4lTunerChannel *v4lchannel = GST_V4L_TUNER_CHANNEL (channel); gint chan; guint signal = 0; /* assert that we're opened and that we're using a known item */ g_return_val_if_fail (GST_V4L_IS_OPEN (v4lelement), 0); g_return_val_if_fail (GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY), 0); g_return_val_if_fail (gst_v4l_tuner_contains_channel (v4lelement, v4lchannel), 0); gst_v4l_get_chan_norm (v4lelement, &chan, NULL); if (chan == GST_V4L_TUNER_CHANNEL (channel)->index && GST_TUNER_CHANNEL_HAS_FLAG (channel, GST_TUNER_CHANNEL_FREQUENCY)) { gst_v4l_get_signal (v4lelement, v4lchannel->tuner, &signal); } return (gint) signal; }
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; }
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; }