Merge branch 'master' into 0.11
[platform/upstream/gstreamer.git] / sys / xvimage / xvimagepool.c
1 /* GStreamer
2  * Copyright (C) <2005> Julien Moutte <julien@moutte.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 /* Object header */
25 #include "xvimagesink.h"
26
27 /* Debugging category */
28 #include <gst/gstinfo.h>
29
30 GST_DEBUG_CATEGORY_EXTERN (gst_debug_xvimagepool);
31 #define GST_CAT_DEFAULT gst_debug_xvimagepool
32
33 static void gst_meta_xvimage_free (GstMetaXvImage * meta, GstBuffer * buffer);
34
35 /* xvimage metadata */
36 const GstMetaInfo *
37 gst_meta_xvimage_get_info (void)
38 {
39   static const GstMetaInfo *meta_xvimage_info = NULL;
40
41   if (meta_xvimage_info == NULL) {
42     meta_xvimage_info = gst_meta_register ("GstMetaXvImage", "GstMetaXvImage",
43         sizeof (GstMetaXvImage),
44         (GstMetaInitFunction) NULL,
45         (GstMetaFreeFunction) gst_meta_xvimage_free,
46         (GstMetaCopyFunction) NULL, (GstMetaTransformFunction) NULL);
47   }
48   return meta_xvimage_info;
49 }
50
51 /* X11 stuff */
52 static gboolean error_caught = FALSE;
53
54 static int
55 gst_xvimagesink_handle_xerror (Display * display, XErrorEvent * xevent)
56 {
57   char error_msg[1024];
58
59   XGetErrorText (display, xevent->error_code, error_msg, 1024);
60   GST_DEBUG ("xvimagesink triggered an XError. error: %s", error_msg);
61   error_caught = TRUE;
62   return 0;
63 }
64
65 GstMetaXvImage *
66 gst_buffer_add_meta_xvimage (GstBuffer * buffer, GstXvImageSink * xvimagesink,
67     gint width, gint height, gint im_format)
68 {
69   int (*handler) (Display *, XErrorEvent *);
70   gboolean success = FALSE;
71   GstXContext *xcontext;
72   GstMetaXvImage *meta;
73
74   xcontext = xvimagesink->xcontext;
75
76   meta =
77       (GstMetaXvImage *) gst_buffer_add_meta (buffer, GST_META_INFO_XVIMAGE,
78       NULL);
79 #ifdef HAVE_XSHM
80   meta->SHMInfo.shmaddr = ((void *) -1);
81   meta->SHMInfo.shmid = -1;
82 #endif
83   meta->width = width;
84   meta->height = height;
85   meta->sink = gst_object_ref (xvimagesink);
86   meta->im_format = im_format;
87
88   GST_DEBUG_OBJECT (xvimagesink, "creating image %p (%dx%d)", buffer,
89       meta->width, meta->height);
90
91   g_mutex_lock (xvimagesink->x_lock);
92
93   /* Setting an error handler to catch failure */
94   error_caught = FALSE;
95   handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
96
97 #ifdef HAVE_XSHM
98   if (xcontext->use_xshm) {
99     int expected_size;
100
101     meta->xvimage = XvShmCreateImage (xcontext->disp,
102         xcontext->xv_port_id,
103         meta->im_format, NULL, meta->width, meta->height, &meta->SHMInfo);
104     if (!meta->xvimage || error_caught) {
105       g_mutex_unlock (xvimagesink->x_lock);
106
107       /* Reset error flag */
108       error_caught = FALSE;
109
110       /* Push a warning */
111       GST_ELEMENT_WARNING (xvimagesink, RESOURCE, WRITE,
112           ("Failed to create output image buffer of %dx%d pixels",
113               meta->width, meta->height),
114           ("could not XShmCreateImage a %dx%d image",
115               meta->width, meta->height));
116
117       /* Retry without XShm */
118       xvimagesink->xcontext->use_xshm = FALSE;
119
120       /* Hold X mutex again to try without XShm */
121       g_mutex_lock (xvimagesink->x_lock);
122       goto no_xshm;
123     }
124
125     /* we have to use the returned data_size for our shm size */
126     meta->size = meta->xvimage->data_size;
127     GST_LOG_OBJECT (xvimagesink, "XShm image size is %" G_GSIZE_FORMAT,
128         meta->size);
129
130     /* calculate the expected size.  This is only for sanity checking the
131      * number we get from X. */
132     switch (meta->im_format) {
133       case GST_MAKE_FOURCC ('I', '4', '2', '0'):
134       case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
135       {
136         gint pitches[3];
137         gint offsets[3];
138         guint plane;
139
140         offsets[0] = 0;
141         pitches[0] = GST_ROUND_UP_4 (meta->width);
142         offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (meta->height);
143         pitches[1] = GST_ROUND_UP_8 (meta->width) / 2;
144         offsets[2] =
145             offsets[1] + pitches[1] * GST_ROUND_UP_2 (meta->height) / 2;
146         pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2;
147
148         expected_size =
149             offsets[2] + pitches[2] * GST_ROUND_UP_2 (meta->height) / 2;
150
151         for (plane = 0; plane < meta->xvimage->num_planes; plane++) {
152           GST_DEBUG_OBJECT (xvimagesink,
153               "Plane %u has a expected pitch of %d bytes, " "offset of %d",
154               plane, pitches[plane], offsets[plane]);
155         }
156         break;
157       }
158       case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
159       case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
160         expected_size = meta->height * GST_ROUND_UP_4 (meta->width * 2);
161         break;
162       default:
163         expected_size = 0;
164         break;
165     }
166     if (expected_size != 0 && meta->size != expected_size) {
167       GST_WARNING_OBJECT (xvimagesink,
168           "unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)",
169           meta->size, expected_size);
170     }
171
172     /* Be verbose about our XvImage stride */
173     {
174       guint plane;
175
176       for (plane = 0; plane < meta->xvimage->num_planes; plane++) {
177         GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a pitch of %d bytes, "
178             "offset of %d", plane, meta->xvimage->pitches[plane],
179             meta->xvimage->offsets[plane]);
180       }
181     }
182
183     /* get shared memory */
184     meta->SHMInfo.shmid = shmget (IPC_PRIVATE, meta->size, IPC_CREAT | 0777);
185     if (meta->SHMInfo.shmid == -1)
186       goto shmget_failed;
187
188     /* attach */
189     meta->SHMInfo.shmaddr = shmat (meta->SHMInfo.shmid, NULL, 0);
190     if (meta->SHMInfo.shmaddr == ((void *) -1))
191       goto shmat_failed;
192
193     /* now we can set up the image data */
194     meta->xvimage->data = meta->SHMInfo.shmaddr;
195     meta->SHMInfo.readOnly = FALSE;
196
197     if (XShmAttach (xcontext->disp, &meta->SHMInfo) == 0)
198       goto xattach_failed;
199
200     XSync (xcontext->disp, FALSE);
201
202     /* Delete the shared memory segment as soon as we everyone is attached.
203      * This way, it will be deleted as soon as we detach later, and not
204      * leaked if we crash. */
205     shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
206
207     GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx",
208         meta->SHMInfo.shmid, meta->SHMInfo.shmseg);
209   } else
210   no_xshm:
211 #endif /* HAVE_XSHM */
212   {
213     meta->xvimage = XvCreateImage (xcontext->disp,
214         xcontext->xv_port_id, meta->im_format, NULL, meta->width, meta->height);
215     if (!meta->xvimage || error_caught)
216       goto create_failed;
217
218     /* we have to use the returned data_size for our image size */
219     meta->size = meta->xvimage->data_size;
220     meta->xvimage->data = g_malloc (meta->size);
221
222     XSync (xcontext->disp, FALSE);
223   }
224
225   /* Reset error handler */
226   error_caught = FALSE;
227   XSetErrorHandler (handler);
228
229   gst_buffer_take_memory (buffer,
230       gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, meta->xvimage->data,
231           NULL, meta->size, 0, meta->size));
232
233   g_mutex_unlock (xvimagesink->x_lock);
234
235   success = TRUE;
236
237 beach:
238   if (!success)
239     meta = NULL;
240
241   return meta;
242
243   /* ERRORS */
244 create_failed:
245   {
246     g_mutex_unlock (xvimagesink->x_lock);
247     /* Reset error handler */
248     error_caught = FALSE;
249     XSetErrorHandler (handler);
250     /* Push an error */
251     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
252         ("Failed to create output image buffer of %dx%d pixels",
253             meta->width, meta->height),
254         ("could not XvShmCreateImage a %dx%d image", meta->width,
255             meta->height));
256     goto beach;
257   }
258 shmget_failed:
259   {
260     g_mutex_unlock (xvimagesink->x_lock);
261     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
262         ("Failed to create output image buffer of %dx%d pixels",
263             meta->width, meta->height),
264         ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
265             meta->size));
266     goto beach;
267   }
268 shmat_failed:
269   {
270     g_mutex_unlock (xvimagesink->x_lock);
271     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
272         ("Failed to create output image buffer of %dx%d pixels",
273             meta->width, meta->height),
274         ("Failed to shmat: %s", g_strerror (errno)));
275     /* Clean up the shared memory segment */
276     shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
277     goto beach;
278   }
279 xattach_failed:
280   {
281     /* Clean up the shared memory segment */
282     shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
283     g_mutex_unlock (xvimagesink->x_lock);
284
285     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
286         ("Failed to create output image buffer of %dx%d pixels",
287             meta->width, meta->height), ("Failed to XShmAttach"));
288     goto beach;
289   }
290 }
291
292 static void
293 gst_meta_xvimage_free (GstMetaXvImage * meta, GstBuffer * buffer)
294 {
295   GstXvImageSink *xvimagesink;
296
297   xvimagesink = meta->sink;
298
299   GST_DEBUG_OBJECT (xvimagesink, "free meta on buffer %p", buffer);
300
301   /* Hold the object lock to ensure the XContext doesn't disappear */
302   GST_OBJECT_LOCK (xvimagesink);
303   /* We might have some buffers destroyed after changing state to NULL */
304   if (xvimagesink->xcontext == NULL) {
305     GST_DEBUG_OBJECT (xvimagesink, "Destroying XvImage after Xcontext");
306 #ifdef HAVE_XSHM
307     /* Need to free the shared memory segment even if the x context
308      * was already cleaned up */
309     if (meta->SHMInfo.shmaddr != ((void *) -1)) {
310       shmdt (meta->SHMInfo.shmaddr);
311     }
312 #endif
313     goto beach;
314   }
315
316   g_mutex_lock (xvimagesink->x_lock);
317
318 #ifdef HAVE_XSHM
319   if (xvimagesink->xcontext->use_xshm) {
320     if (meta->SHMInfo.shmaddr != ((void *) -1)) {
321       GST_DEBUG_OBJECT (xvimagesink, "XServer ShmDetaching from 0x%x id 0x%lx",
322           meta->SHMInfo.shmid, meta->SHMInfo.shmseg);
323       XShmDetach (xvimagesink->xcontext->disp, &meta->SHMInfo);
324       XSync (xvimagesink->xcontext->disp, FALSE);
325       shmdt (meta->SHMInfo.shmaddr);
326       meta->SHMInfo.shmaddr = (void *) -1;
327     }
328     if (meta->xvimage)
329       XFree (meta->xvimage);
330   } else
331 #endif /* HAVE_XSHM */
332   {
333     if (meta->xvimage) {
334       g_free (meta->xvimage->data);
335       XFree (meta->xvimage);
336     }
337   }
338
339   XSync (xvimagesink->xcontext->disp, FALSE);
340
341   g_mutex_unlock (xvimagesink->x_lock);
342
343 beach:
344   GST_OBJECT_UNLOCK (xvimagesink);
345
346   gst_object_unref (meta->sink);
347 }
348
349 GstBuffer *
350 gst_xvimage_buffer_new (GstXvImageSink * xvimagesink, gint width, gint height,
351     gint im_format)
352 {
353   GstBuffer *buffer;
354   GstMetaXvImage *meta;
355
356   buffer = gst_buffer_new ();
357   meta =
358       gst_buffer_add_meta_xvimage (buffer, xvimagesink, width, height,
359       im_format);
360   if (meta == NULL) {
361     gst_buffer_unref (buffer);
362     buffer = NULL;
363   }
364   return buffer;
365 }
366
367 #ifdef HAVE_XSHM
368 /* This function checks that it is actually really possible to create an image
369    using XShm */
370 gboolean
371 gst_xvimagesink_check_xshm_calls (GstXvImageSink * xvimagesink,
372     GstXContext * xcontext)
373 {
374   XvImage *xvimage;
375   XShmSegmentInfo SHMInfo;
376   size_t size;
377   int (*handler) (Display *, XErrorEvent *);
378   gboolean result = FALSE;
379   gboolean did_attach = FALSE;
380
381   g_return_val_if_fail (xcontext != NULL, FALSE);
382
383   /* Sync to ensure any older errors are already processed */
384   XSync (xcontext->disp, FALSE);
385
386   /* Set defaults so we don't free these later unnecessarily */
387   SHMInfo.shmaddr = ((void *) -1);
388   SHMInfo.shmid = -1;
389
390   /* Setting an error handler to catch failure */
391   error_caught = FALSE;
392   handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
393
394   /* Trying to create a 1x1 picture */
395   GST_DEBUG ("XvShmCreateImage of 1x1");
396   xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id,
397       xcontext->im_format, NULL, 1, 1, &SHMInfo);
398
399   /* Might cause an error, sync to ensure it is noticed */
400   XSync (xcontext->disp, FALSE);
401   if (!xvimage || error_caught) {
402     GST_WARNING ("could not XvShmCreateImage a 1x1 image");
403     goto beach;
404   }
405   size = xvimage->data_size;
406
407   SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
408   if (SHMInfo.shmid == -1) {
409     GST_WARNING ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
410         size);
411     goto beach;
412   }
413
414   SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0);
415   if (SHMInfo.shmaddr == ((void *) -1)) {
416     GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
417     /* Clean up the shared memory segment */
418     shmctl (SHMInfo.shmid, IPC_RMID, NULL);
419     goto beach;
420   }
421
422   xvimage->data = SHMInfo.shmaddr;
423   SHMInfo.readOnly = FALSE;
424
425   if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
426     GST_WARNING ("Failed to XShmAttach");
427     /* Clean up the shared memory segment */
428     shmctl (SHMInfo.shmid, IPC_RMID, NULL);
429     goto beach;
430   }
431
432   /* Sync to ensure we see any errors we caused */
433   XSync (xcontext->disp, FALSE);
434
435   /* Delete the shared memory segment as soon as everyone is attached.
436    * This way, it will be deleted as soon as we detach later, and not
437    * leaked if we crash. */
438   shmctl (SHMInfo.shmid, IPC_RMID, NULL);
439
440   if (!error_caught) {
441     GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
442         SHMInfo.shmseg);
443
444     did_attach = TRUE;
445     /* store whether we succeeded in result */
446     result = TRUE;
447   } else {
448     GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
449         "Not using shared memory.");
450   }
451
452 beach:
453   /* Sync to ensure we swallow any errors we caused and reset error_caught */
454   XSync (xcontext->disp, FALSE);
455
456   error_caught = FALSE;
457   XSetErrorHandler (handler);
458
459   if (did_attach) {
460     GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
461         SHMInfo.shmid, SHMInfo.shmseg);
462     XShmDetach (xcontext->disp, &SHMInfo);
463     XSync (xcontext->disp, FALSE);
464   }
465   if (SHMInfo.shmaddr != ((void *) -1))
466     shmdt (SHMInfo.shmaddr);
467   if (xvimage)
468     XFree (xvimage);
469   return result;
470 }
471 #endif /* HAVE_XSHM */
472
473 /* bufferpool */
474 static void gst_xvimage_buffer_pool_finalize (GObject * object);
475
476 #define GST_XVIMAGE_BUFFER_POOL_GET_PRIVATE(obj)  \
477    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_XVIMAGE_BUFFER_POOL, GstXvImageBufferPoolPrivate))
478
479 struct _GstXvImageBufferPoolPrivate
480 {
481   GstCaps *caps;
482   gint width, height;
483   gint im_format;
484 };
485
486 G_DEFINE_TYPE (GstXvImageBufferPool, gst_xvimage_buffer_pool,
487     GST_TYPE_BUFFER_POOL);
488
489 static gboolean
490 xvimage_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
491 {
492   GstXvImageBufferPool *xvpool = GST_XVIMAGE_BUFFER_POOL_CAST (pool);
493   GstXvImageBufferPoolPrivate *priv = xvpool->priv;
494   GstStructure *structure;
495   gint width, height;
496   const GstCaps *caps;
497
498   if (!gst_buffer_pool_config_get (config, &caps, NULL, NULL, NULL, NULL,
499           NULL, NULL))
500     goto wrong_config;
501
502   if (caps == NULL)
503     goto no_caps;
504
505   /* now parse the caps from the config */
506   structure = gst_caps_get_structure (caps, 0);
507
508   if (!gst_structure_get_int (structure, "width", &width) ||
509       !gst_structure_get_int (structure, "height", &height))
510     goto wrong_caps;
511
512   GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT, width, height, caps);
513
514   /* keep track of the width and height and caps */
515   if (priv->caps)
516     gst_caps_unref (priv->caps);
517   priv->caps = gst_caps_copy (caps);
518   priv->width = width;
519   priv->height = height;
520   priv->im_format =
521       gst_xvimagesink_get_format_from_caps (xvpool->sink, (GstCaps *) caps);
522
523   if (priv->im_format == -1) {
524     GST_WARNING_OBJECT (xvpool->sink, "failed to get format from caps %"
525         GST_PTR_FORMAT, caps);
526     GST_ELEMENT_ERROR (xvpool->sink, RESOURCE, WRITE,
527         ("Failed to create output image buffer of %dx%d pixels",
528             priv->width, priv->height), ("Invalid input caps"));
529     goto wrong_config;
530   }
531
532   return TRUE;
533
534   /* ERRORS */
535 wrong_config:
536   {
537     GST_WARNING_OBJECT (pool, "invalid config");
538     return FALSE;
539   }
540 no_caps:
541   {
542     GST_WARNING_OBJECT (pool, "no caps in config");
543     return FALSE;
544   }
545 wrong_caps:
546   {
547     GST_WARNING_OBJECT (pool,
548         "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
549     return FALSE;
550   }
551 }
552
553 /* This function handles GstXImageBuffer creation depending on XShm availability */
554 static GstFlowReturn
555 xvimage_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
556     GstBufferPoolParams * params)
557 {
558   GstXvImageBufferPool *xvpool = GST_XVIMAGE_BUFFER_POOL_CAST (pool);
559   GstXvImageBufferPoolPrivate *priv = xvpool->priv;
560   GstBuffer *xvimage;
561
562   xvimage =
563       gst_xvimage_buffer_new (xvpool->sink, priv->width, priv->height,
564       priv->im_format);
565   if (xvimage == NULL)
566     goto no_buffer;
567
568   *buffer = xvimage;
569
570   return GST_FLOW_OK;
571
572   /* ERROR */
573 no_buffer:
574   {
575     GST_WARNING_OBJECT (pool, "can't create image");
576     return GST_FLOW_ERROR;
577   }
578 }
579
580 static void
581 xvimage_buffer_pool_free (GstBufferPool * pool, GstBuffer * buffer)
582 {
583   gst_buffer_unref (buffer);
584 }
585
586 GstBufferPool *
587 gst_xvimage_buffer_pool_new (GstXvImageSink * xvimagesink)
588 {
589   GstXvImageBufferPool *pool;
590
591   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
592
593   pool = g_object_new (GST_TYPE_XVIMAGE_BUFFER_POOL, NULL);
594   pool->sink = gst_object_ref (xvimagesink);
595
596   GST_LOG_OBJECT (pool, "new XvImage buffer pool %p", pool);
597
598   return GST_BUFFER_POOL_CAST (pool);
599 }
600
601 static void
602 gst_xvimage_buffer_pool_class_init (GstXvImageBufferPoolClass * klass)
603 {
604   GObjectClass *gobject_class = (GObjectClass *) klass;
605   GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
606
607   g_type_class_add_private (klass, sizeof (GstXvImageBufferPoolPrivate));
608
609   gobject_class->finalize = gst_xvimage_buffer_pool_finalize;
610
611   gstbufferpool_class->set_config = xvimage_buffer_pool_set_config;
612   gstbufferpool_class->alloc_buffer = xvimage_buffer_pool_alloc;
613   gstbufferpool_class->free_buffer = xvimage_buffer_pool_free;
614 }
615
616 static void
617 gst_xvimage_buffer_pool_init (GstXvImageBufferPool * pool)
618 {
619   pool->priv = GST_XVIMAGE_BUFFER_POOL_GET_PRIVATE (pool);
620 }
621
622 static void
623 gst_xvimage_buffer_pool_finalize (GObject * object)
624 {
625   GstXvImageBufferPool *pool = GST_XVIMAGE_BUFFER_POOL_CAST (object);
626   GstXvImageBufferPoolPrivate *priv = pool->priv;
627
628   GST_LOG_OBJECT (pool, "finalize XvImage buffer pool %p", pool);
629
630   if (priv->caps)
631     gst_caps_unref (priv->caps);
632   gst_object_unref (pool->sink);
633
634   G_OBJECT_CLASS (gst_xvimage_buffer_pool_parent_class)->finalize (object);
635 }
636
637 /* This function tries to get a format matching with a given caps in the
638    supported list of formats we generated in gst_xvimagesink_get_xv_support */
639 gint
640 gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
641     GstCaps * caps)
642 {
643   GList *list = NULL;
644
645   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
646
647   list = xvimagesink->xcontext->formats_list;
648
649   while (list) {
650     GstXvImageFormat *format = list->data;
651
652     if (format) {
653       if (gst_caps_can_intersect (caps, format->caps)) {
654         return format->format;
655       }
656     }
657     list = g_list_next (list);
658   }
659
660   return -1;
661 }