static GstCaps * gst_v4l2sink_get_caps (GstBaseSink * bsink) { GstV4l2Sink *v4l2sink = GST_V4L2SINK (bsink); GstCaps *ret; GSList *walk; GSList *formats; if (!GST_V4L2_IS_OPEN (v4l2sink->v4l2object)) { /* FIXME: copy? */ GST_DEBUG_OBJECT (v4l2sink, "device is not open"); return gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (v4l2sink))); } if (v4l2sink->probed_caps) { LOG_CAPS (v4l2sink, v4l2sink->probed_caps); return gst_caps_ref (v4l2sink->probed_caps); } formats = gst_v4l2_object_get_format_list (v4l2sink->v4l2object); ret = gst_caps_new_empty (); for (walk = v4l2sink->v4l2object->formats; walk; walk = walk->next) { struct v4l2_fmtdesc *format; GstStructure *template;
static gboolean gst_v4l2sink_set_caps (GstBaseSink * bsink, GstCaps * caps) { GstV4l2Sink *v4l2sink = GST_V4L2SINK (bsink); GstV4l2Object *obj = v4l2sink->v4l2object; LOG_CAPS (v4l2sink, caps); if (!GST_V4L2_IS_OPEN (v4l2sink->v4l2object)) { GST_DEBUG_OBJECT (v4l2sink, "device is not open"); return FALSE; } /* make sure the caps changed before doing anything */ if (gst_v4l2_object_caps_equal (obj, caps)) return TRUE; if (!gst_v4l2_object_stop (obj)) goto stop_failed; if (!gst_v4l2_object_set_format (v4l2sink->v4l2object, caps)) goto invalid_format; gst_v4l2sink_sync_overlay_fields (v4l2sink); gst_v4l2sink_sync_crop_fields (v4l2sink); #ifdef HAVE_XVIDEO gst_v4l2_video_overlay_prepare_window_handle (v4l2sink->v4l2object, TRUE); #endif GST_INFO_OBJECT (v4l2sink, "outputting buffers via mmap()"); v4l2sink->video_width = GST_V4L2_WIDTH (v4l2sink->v4l2object); v4l2sink->video_height = GST_V4L2_HEIGHT (v4l2sink->v4l2object); /* TODO: videosink width/height should be scaled according to * pixel-aspect-ratio */ GST_VIDEO_SINK_WIDTH (v4l2sink) = v4l2sink->video_width; GST_VIDEO_SINK_HEIGHT (v4l2sink) = v4l2sink->video_height; return TRUE; /* ERRORS */ stop_failed: { GST_DEBUG_OBJECT (v4l2sink, "failed to stop streaming"); return FALSE; } invalid_format: { /* error already posted */ GST_DEBUG_OBJECT (v4l2sink, "can't set format"); return FALSE; } }
static gboolean gst_v4l2src_negotiate (GstBaseSrc * basesrc) { GstV4l2Src *v4l2src; GstV4l2Object *obj; GstCaps *thiscaps; GstCaps *caps = NULL; GstCaps *peercaps = NULL; gboolean result = FALSE; v4l2src = GST_V4L2SRC (basesrc); obj = v4l2src->v4l2object; /* We don't allow renegotiation, just return TRUE in that case */ if (GST_V4L2_IS_ACTIVE (obj)) return TRUE; /* first see what is possible on our source pad */ thiscaps = gst_pad_query_caps (GST_BASE_SRC_PAD (basesrc), NULL); GST_DEBUG_OBJECT (basesrc, "caps of src: %" GST_PTR_FORMAT, thiscaps); LOG_CAPS (basesrc, thiscaps); /* nothing or anything is allowed, we're done */ if (thiscaps == NULL || gst_caps_is_any (thiscaps)) goto no_nego_needed; /* get the peer caps without a filter as we'll filter ourselves later on */ peercaps = gst_pad_peer_query_caps (GST_BASE_SRC_PAD (basesrc), NULL); GST_DEBUG_OBJECT (basesrc, "caps of peer: %" GST_PTR_FORMAT, peercaps); LOG_CAPS (basesrc, peercaps); if (peercaps && !gst_caps_is_any (peercaps)) { GstCaps *icaps = NULL; int i; /* Prefer the first caps we are compatible with that the peer proposed */ for (i = 0; i < gst_caps_get_size (peercaps); i++) { /* get intersection */ GstCaps *ipcaps = gst_caps_copy_nth (peercaps, i); GST_DEBUG_OBJECT (basesrc, "peer: %" GST_PTR_FORMAT, ipcaps); LOG_CAPS (basesrc, ipcaps); icaps = gst_caps_intersect (thiscaps, ipcaps); gst_caps_unref (ipcaps); if (!gst_caps_is_empty (icaps)) break; gst_caps_unref (icaps); icaps = NULL; } GST_DEBUG_OBJECT (basesrc, "intersect: %" GST_PTR_FORMAT, icaps); LOG_CAPS (basesrc, icaps); if (icaps) { /* If there are multiple intersections pick the one with the smallest * resolution strictly bigger then the first peer caps */ if (gst_caps_get_size (icaps) > 1) { GstStructure *s = gst_caps_get_structure (peercaps, 0); int best = 0; int twidth, theight; int width = G_MAXINT, height = G_MAXINT; if (gst_structure_get_int (s, "width", &twidth) && gst_structure_get_int (s, "height", &theight)) { /* Walk the structure backwards to get the first entry of the * smallest resolution bigger (or equal to) the preferred resolution) */ for (i = gst_caps_get_size (icaps) - 1; i >= 0; i--) { GstStructure *is = gst_caps_get_structure (icaps, i); int w, h; if (gst_structure_get_int (is, "width", &w) && gst_structure_get_int (is, "height", &h)) { if (w >= twidth && w <= width && h >= theight && h <= height) { width = w; height = h; best = i; } } } } caps = gst_caps_copy_nth (icaps, best); gst_caps_unref (icaps); } else { caps = icaps; } } gst_caps_unref (thiscaps); } else { /* no peer or peer have ANY caps, work with our own caps then */ caps = thiscaps; } if (peercaps) gst_caps_unref (peercaps); if (caps) { caps = gst_caps_truncate (caps); /* now fixate */ if (!gst_caps_is_empty (caps)) { caps = gst_v4l2src_fixate (basesrc, caps); GST_DEBUG_OBJECT (basesrc, "fixated to: %" GST_PTR_FORMAT, caps); LOG_CAPS (basesrc, caps); if (gst_caps_is_any (caps)) { /* hmm, still anything, so element can do anything and * nego is not needed */ result = TRUE; } else if (gst_caps_is_fixed (caps)) { /* yay, fixed caps, use those then */ result = gst_base_src_set_caps (basesrc, caps); } } gst_caps_unref (caps); } return result; no_nego_needed: { GST_DEBUG_OBJECT (basesrc, "no negotiation needed"); if (thiscaps) gst_caps_unref (thiscaps); return TRUE; } }