diff --git a/ChangeLog b/ChangeLog
index bb280cc797..f228265fbb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2006-01-21  Julien MOUTTE  <julien@moutte.net>
+
+	* sys/xvimage/xvimagesink.c: (gst_xvimagesink_buffer_alloc):
+	  I think one day i'll completely undestand how caps negotiation
+	  is supposed to work. This refactoring handles buffer_alloc
+	  called with caps we can't handle. We definitely don't want a
+	  set_caps with those caps, so we define and allocate a buffer
+	  we would like to receive.
+
 2006-01-19  Tim-Philipp Müller  <tim at centricular dot net>
 
 	* gst/playback/gstplaybasebin.c: (setup_source):
diff --git a/sys/xvimage/xvimagesink.c b/sys/xvimage/xvimagesink.c
index 8b2e299f6c..85d52ad736 100644
--- a/sys/xvimage/xvimagesink.c
+++ b/sys/xvimage/xvimagesink.c
@@ -1804,11 +1804,86 @@ static GstFlowReturn
 gst_xvimagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
     GstCaps * caps, GstBuffer ** buf)
 {
+  GstFlowReturn ret = GST_FLOW_OK;
   GstXvImageSink *xvimagesink;
   GstXvImageBuffer *xvimage = NULL;
+  GstCaps *intersection = NULL;
+  GstStructure *structure = NULL;
+  gint width, height, image_format;
 
   xvimagesink = GST_XVIMAGESINK (bsink);
 
+  GST_DEBUG_OBJECT (xvimagesink, "buffer alloc requested with caps %"
+      GST_PTR_FORMAT "intersecting with our caps %" GST_PTR_FORMAT, caps,
+      xvimagesink->xcontext->caps);
+
+  /* Check the caps against our xcontext */
+  intersection = gst_caps_intersect (xvimagesink->xcontext->caps, caps);
+  GST_DEBUG_OBJECT (xvimagesink, "intersection in buffer alloc returned %"
+      GST_PTR_FORMAT, intersection);
+
+  if (gst_caps_is_empty (intersection)) {
+    /* So we don't support this kind of buffer, let's define one we'd like */
+    GstCaps *new_caps = gst_caps_copy (caps);
+
+    structure = gst_caps_get_structure (new_caps, 0);
+
+    /* Try with YUV first */
+    gst_structure_set_name (structure, "video/x-raw-yuv");
+    gst_structure_remove_field (structure, "format");
+    gst_structure_remove_field (structure, "endianness");
+    gst_structure_remove_field (structure, "depth");
+    gst_structure_remove_field (structure, "bpp");
+    gst_structure_remove_field (structure, "red_mask");
+    gst_structure_remove_field (structure, "green_mask");
+    gst_structure_remove_field (structure, "blue_mask");
+    gst_structure_remove_field (structure, "alpha_mask");
+
+    /* Reuse intersection with Xcontext */
+    gst_caps_unref (intersection);
+    intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
+
+    if (gst_caps_is_empty (intersection)) {
+      /* Now try with RGB */
+      gst_structure_set_name (structure, "video/x-raw-rgb");
+      /* And interset again */
+      gst_caps_unref (intersection);
+      intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
+
+      if (gst_caps_is_empty (intersection)) {
+        GST_WARNING_OBJECT (xvimagesink, "we were requested a buffer with "
+            "caps %" GST_PTR_FORMAT "but our xcontext caps %" GST_PTR_FORMAT
+            "are completely incompatible with those caps", new_caps,
+            xvimagesink->xcontext->caps);
+        gst_caps_unref (new_caps);
+        ret = GST_FLOW_UNEXPECTED;
+        goto beach;
+      }
+    }
+
+    /* Clean this copy */
+    gst_caps_unref (new_caps);
+    /* We want fixed caps */
+    gst_caps_truncate (intersection);
+
+    GST_DEBUG_OBJECT (xvimagesink, "allocating a buffer with caps %"
+        GST_PTR_FORMAT, intersection);
+  }
+
+  /* Get image format from caps */
+  image_format = gst_xvimagesink_get_format_from_caps (xvimagesink,
+      intersection);
+
+  /* Get geometry from caps */
+  structure = gst_caps_get_structure (intersection, 0);
+  if (!gst_structure_get_int (structure, "width", &width) ||
+      !gst_structure_get_int (structure, "height", &height) || !image_format) {
+    GST_WARNING_OBJECT (xvimagesink, "invalid caps for buffer allocation %"
+        GST_PTR_FORMAT, intersection);
+    ret = GST_FLOW_UNEXPECTED;
+    goto beach;
+  }
+
   g_mutex_lock (xvimagesink->pool_lock);
 
   /* Walking through the pool cleaning unusable images and searching for a
@@ -1822,9 +1897,8 @@ gst_xvimagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
           xvimagesink->image_pool);
 
       /* We check for geometry or image format changes */
-      if ((xvimage->width != xvimagesink->video_width) ||
-          (xvimage->height != xvimagesink->video_height) ||
-          (xvimage->im_format != xvimagesink->xcontext->im_format)) {
+      if ((xvimage->width != width) ||
+          (xvimage->height != height) || (xvimage->im_format != image_format)) {
         /* This image is unusable. Destroying... */
         gst_xvimage_buffer_free (xvimage);
         xvimage = NULL;
@@ -1841,14 +1915,21 @@ gst_xvimagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
   if (!xvimage) {
     /* We found no suitable image in the pool. Creating... */
     GST_DEBUG_OBJECT (xvimagesink, "no usable image in pool, creating xvimage");
-    xvimage = gst_xvimagesink_xvimage_new (xvimagesink, caps);
+    xvimage = gst_xvimagesink_xvimage_new (xvimagesink, intersection);
   }
+
   if (xvimage) {
-    gst_buffer_set_caps (GST_BUFFER (xvimage), caps);
+    gst_buffer_set_caps (GST_BUFFER (xvimage), intersection);
   }
+
   *buf = GST_BUFFER (xvimage);
 
-  return GST_FLOW_OK;
+beach:
+  if (intersection) {
+    gst_caps_unref (intersection);
+  }
+
+  return ret;
 }
 
 /* Interfaces stuff */