xvimagesink: port to new GLib thread API
[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 /* Helper functions */
31 #include <gst/video/video.h>
32 #include <gst/video/gstvideometa.h>
33 #include <gst/video/gstvideopool.h>
34
35
36 GST_DEBUG_CATEGORY_EXTERN (gst_debug_xvimagepool);
37 #define GST_CAT_DEFAULT gst_debug_xvimagepool
38
39
40 struct _GstXvImageBufferPoolPrivate
41 {
42   GstCaps *caps;
43   gint im_format;
44   GstVideoInfo info;
45   GstVideoAlignment align;
46   guint padded_width;
47   guint padded_height;
48   gboolean add_metavideo;
49   gboolean need_alignment;
50 };
51
52 static void gst_xvimage_meta_free (GstXvImageMeta * meta, GstBuffer * buffer);
53
54 /* xvimage metadata */
55 GType
56 gst_xvimage_meta_api_get_type (void)
57 {
58   static volatile GType type;
59   static const gchar *tags[] =
60       { "memory", "size", "colorspace", "orientation", NULL };
61
62   if (g_once_init_enter (&type)) {
63     GType _type = gst_meta_api_type_register ("GstXvImageMetaAPI", tags);
64     g_once_init_leave (&type, _type);
65   }
66   return type;
67 }
68
69 const GstMetaInfo *
70 gst_xvimage_meta_get_info (void)
71 {
72   static const GstMetaInfo *xvimage_meta_info = NULL;
73
74   if (xvimage_meta_info == NULL) {
75     xvimage_meta_info =
76         gst_meta_register (GST_XVIMAGE_META_API_TYPE, "GstXvImageMeta",
77         sizeof (GstXvImageMeta), (GstMetaInitFunction) NULL,
78         (GstMetaFreeFunction) gst_xvimage_meta_free,
79         (GstMetaTransformFunction) NULL);
80   }
81   return xvimage_meta_info;
82 }
83
84 /* X11 stuff */
85 static gboolean error_caught = FALSE;
86
87 static int
88 gst_xvimagesink_handle_xerror (Display * display, XErrorEvent * xevent)
89 {
90   char error_msg[1024];
91
92   XGetErrorText (display, xevent->error_code, error_msg, 1024);
93   GST_DEBUG ("xvimagesink triggered an XError. error: %s", error_msg);
94   error_caught = TRUE;
95   return 0;
96 }
97
98 static GstXvImageMeta *
99 gst_buffer_add_xvimage_meta (GstBuffer * buffer, GstXvImageBufferPool * xvpool)
100 {
101   GstXvImageSink *xvimagesink;
102   int (*handler) (Display *, XErrorEvent *);
103   gboolean success = FALSE;
104   GstXContext *xcontext;
105   GstXvImageMeta *meta;
106   gint width, height, im_format, align = 15, offset;
107   GstXvImageBufferPoolPrivate *priv;
108
109   priv = xvpool->priv;
110   xvimagesink = xvpool->sink;
111   xcontext = xvimagesink->xcontext;
112
113   width = priv->padded_width;
114   height = priv->padded_height;
115   im_format = priv->im_format;
116
117   meta =
118       (GstXvImageMeta *) gst_buffer_add_meta (buffer, GST_XVIMAGE_META_INFO,
119       NULL);
120 #ifdef HAVE_XSHM
121   meta->SHMInfo.shmaddr = ((void *) -1);
122   meta->SHMInfo.shmid = -1;
123 #endif
124   meta->x = priv->align.padding_left;
125   meta->y = priv->align.padding_top;
126   meta->width = priv->info.width;
127   meta->height = priv->info.height;
128   meta->sink = gst_object_ref (xvimagesink);
129   meta->im_format = im_format;
130
131   GST_DEBUG_OBJECT (xvimagesink, "creating image %p (%dx%d)", buffer,
132       width, height);
133
134   g_mutex_lock (&xvimagesink->x_lock);
135
136   /* Setting an error handler to catch failure */
137   error_caught = FALSE;
138   handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
139
140 #ifdef HAVE_XSHM
141   if (xcontext->use_xshm) {
142     int expected_size;
143
144     meta->xvimage = XvShmCreateImage (xcontext->disp,
145         xcontext->xv_port_id, im_format, NULL, width, height, &meta->SHMInfo);
146     if (!meta->xvimage || error_caught) {
147       g_mutex_unlock (&xvimagesink->x_lock);
148
149       /* Reset error flag */
150       error_caught = FALSE;
151
152       /* Push a warning */
153       GST_ELEMENT_WARNING (xvimagesink, RESOURCE, WRITE,
154           ("Failed to create output image buffer of %dx%d pixels",
155               width, height),
156           ("could not XShmCreateImage a %dx%d image", width, height));
157
158       /* Retry without XShm */
159       xvimagesink->xcontext->use_xshm = FALSE;
160
161       /* Hold X mutex again to try without XShm */
162       g_mutex_lock (&xvimagesink->x_lock);
163       goto no_xshm;
164     }
165
166     /* we have to use the returned data_size for our shm size */
167     meta->size = meta->xvimage->data_size;
168     GST_LOG_OBJECT (xvimagesink, "XShm image size is %" G_GSIZE_FORMAT,
169         meta->size);
170
171     /* calculate the expected size.  This is only for sanity checking the
172      * number we get from X. */
173     switch (im_format) {
174       case GST_MAKE_FOURCC ('I', '4', '2', '0'):
175       case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
176       {
177         gint pitches[3];
178         gint offsets[3];
179         guint plane;
180
181         offsets[0] = 0;
182         pitches[0] = GST_ROUND_UP_4 (width);
183         offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (height);
184         pitches[1] = GST_ROUND_UP_8 (width) / 2;
185         offsets[2] = offsets[1] + pitches[1] * GST_ROUND_UP_2 (height) / 2;
186         pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2;
187
188         expected_size = offsets[2] + pitches[2] * GST_ROUND_UP_2 (height) / 2;
189
190         for (plane = 0; plane < meta->xvimage->num_planes; plane++) {
191           GST_DEBUG_OBJECT (xvimagesink,
192               "Plane %u has a expected pitch of %d bytes, " "offset of %d",
193               plane, pitches[plane], offsets[plane]);
194         }
195         break;
196       }
197       case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
198       case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
199         expected_size = height * GST_ROUND_UP_4 (width * 2);
200         break;
201       default:
202         expected_size = 0;
203         break;
204     }
205     if (expected_size != 0 && meta->size != expected_size) {
206       GST_WARNING_OBJECT (xvimagesink,
207           "unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)",
208           meta->size, expected_size);
209     }
210
211     /* Be verbose about our XvImage stride */
212     {
213       guint plane;
214
215       for (plane = 0; plane < meta->xvimage->num_planes; plane++) {
216         GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a pitch of %d bytes, "
217             "offset of %d", plane, meta->xvimage->pitches[plane],
218             meta->xvimage->offsets[plane]);
219       }
220     }
221
222     /* get shared memory */
223     meta->SHMInfo.shmid =
224         shmget (IPC_PRIVATE, meta->size + align, IPC_CREAT | 0777);
225     if (meta->SHMInfo.shmid == -1)
226       goto shmget_failed;
227
228     /* attach */
229     meta->SHMInfo.shmaddr = shmat (meta->SHMInfo.shmid, NULL, 0);
230     if (meta->SHMInfo.shmaddr == ((void *) -1))
231       goto shmat_failed;
232
233     /* now we can set up the image data */
234     meta->xvimage->data = meta->SHMInfo.shmaddr;
235     meta->SHMInfo.readOnly = FALSE;
236
237     if (XShmAttach (xcontext->disp, &meta->SHMInfo) == 0)
238       goto xattach_failed;
239
240     XSync (xcontext->disp, FALSE);
241
242     /* Delete the shared memory segment as soon as we everyone is attached.
243      * This way, it will be deleted as soon as we detach later, and not
244      * leaked if we crash. */
245     shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
246
247     GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx",
248         meta->SHMInfo.shmid, meta->SHMInfo.shmseg);
249   } else
250   no_xshm:
251 #endif /* HAVE_XSHM */
252   {
253     meta->xvimage = XvCreateImage (xcontext->disp,
254         xcontext->xv_port_id, im_format, NULL, width, height);
255     if (!meta->xvimage || error_caught)
256       goto create_failed;
257
258     /* we have to use the returned data_size for our image size */
259     meta->size = meta->xvimage->data_size;
260     meta->xvimage->data = g_malloc (meta->size + align);
261
262     XSync (xcontext->disp, FALSE);
263   }
264
265   if ((offset = ((guintptr) meta->xvimage->data & align)))
266     offset = (align + 1) - offset;
267
268   GST_DEBUG_OBJECT (xvimagesink, "memory %p, align %d, offset %d",
269       meta->xvimage->data, align, offset);
270
271   /* Reset error handler */
272   error_caught = FALSE;
273   XSetErrorHandler (handler);
274
275   gst_buffer_append_memory (buffer,
276       gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, meta->xvimage->data,
277           meta->size + align, offset, meta->size, NULL, NULL));
278
279   g_mutex_unlock (&xvimagesink->x_lock);
280
281   success = TRUE;
282
283 beach:
284   if (!success)
285     meta = NULL;
286
287   return meta;
288
289   /* ERRORS */
290 create_failed:
291   {
292     g_mutex_unlock (&xvimagesink->x_lock);
293     /* Reset error handler */
294     error_caught = FALSE;
295     XSetErrorHandler (handler);
296     /* Push an error */
297     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
298         ("Failed to create output image buffer of %dx%d pixels",
299             width, height),
300         ("could not XvShmCreateImage a %dx%d image", width, height));
301     goto beach;
302   }
303 #ifdef HAVE_XSHM
304 shmget_failed:
305   {
306     g_mutex_unlock (&xvimagesink->x_lock);
307     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
308         ("Failed to create output image buffer of %dx%d pixels",
309             width, height),
310         ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
311             meta->size));
312     goto beach;
313   }
314 shmat_failed:
315   {
316     g_mutex_unlock (&xvimagesink->x_lock);
317     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
318         ("Failed to create output image buffer of %dx%d pixels",
319             width, height), ("Failed to shmat: %s", g_strerror (errno)));
320     /* Clean up the shared memory segment */
321     shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
322     goto beach;
323   }
324 xattach_failed:
325   {
326     /* Clean up the shared memory segment */
327     shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
328     g_mutex_unlock (&xvimagesink->x_lock);
329
330     GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
331         ("Failed to create output image buffer of %dx%d pixels",
332             width, height), ("Failed to XShmAttach"));
333     goto beach;
334   }
335 #endif
336 }
337
338 static void
339 gst_xvimage_meta_free (GstXvImageMeta * meta, GstBuffer * buffer)
340 {
341   GstXvImageSink *xvimagesink;
342
343   xvimagesink = meta->sink;
344
345   GST_DEBUG_OBJECT (xvimagesink, "free meta on buffer %p", buffer);
346
347   /* Hold the object lock to ensure the XContext doesn't disappear */
348   GST_OBJECT_LOCK (xvimagesink);
349   /* We might have some buffers destroyed after changing state to NULL */
350   if (xvimagesink->xcontext == NULL) {
351     GST_DEBUG_OBJECT (xvimagesink, "Destroying XvImage after Xcontext");
352 #ifdef HAVE_XSHM
353     /* Need to free the shared memory segment even if the x context
354      * was already cleaned up */
355     if (meta->SHMInfo.shmaddr != ((void *) -1)) {
356       shmdt (meta->SHMInfo.shmaddr);
357     }
358 #endif
359     if (meta->xvimage)
360       XFree (meta->xvimage);
361     goto beach;
362   }
363
364   g_mutex_lock (&xvimagesink->x_lock);
365
366 #ifdef HAVE_XSHM
367   if (xvimagesink->xcontext->use_xshm) {
368     if (meta->SHMInfo.shmaddr != ((void *) -1)) {
369       GST_DEBUG_OBJECT (xvimagesink, "XServer ShmDetaching from 0x%x id 0x%lx",
370           meta->SHMInfo.shmid, meta->SHMInfo.shmseg);
371       XShmDetach (xvimagesink->xcontext->disp, &meta->SHMInfo);
372       XSync (xvimagesink->xcontext->disp, FALSE);
373       shmdt (meta->SHMInfo.shmaddr);
374       meta->SHMInfo.shmaddr = (void *) -1;
375     }
376     if (meta->xvimage)
377       XFree (meta->xvimage);
378   } else
379 #endif /* HAVE_XSHM */
380   {
381     if (meta->xvimage) {
382       g_free (meta->xvimage->data);
383       XFree (meta->xvimage);
384     }
385   }
386
387   XSync (xvimagesink->xcontext->disp, FALSE);
388
389   g_mutex_unlock (&xvimagesink->x_lock);
390
391 beach:
392   GST_OBJECT_UNLOCK (xvimagesink);
393
394   gst_object_unref (meta->sink);
395 }
396
397 #ifdef HAVE_XSHM
398 /* This function checks that it is actually really possible to create an image
399    using XShm */
400 gboolean
401 gst_xvimagesink_check_xshm_calls (GstXvImageSink * xvimagesink,
402     GstXContext * xcontext)
403 {
404   XvImage *xvimage;
405   XShmSegmentInfo SHMInfo;
406   size_t size;
407   int (*handler) (Display *, XErrorEvent *);
408   gboolean result = FALSE;
409   gboolean did_attach = FALSE;
410
411   g_return_val_if_fail (xcontext != NULL, FALSE);
412
413   /* Sync to ensure any older errors are already processed */
414   XSync (xcontext->disp, FALSE);
415
416   /* Set defaults so we don't free these later unnecessarily */
417   SHMInfo.shmaddr = ((void *) -1);
418   SHMInfo.shmid = -1;
419
420   /* Setting an error handler to catch failure */
421   error_caught = FALSE;
422   handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
423
424   /* Trying to create a 1x1 picture */
425   GST_DEBUG ("XvShmCreateImage of 1x1");
426   xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id,
427       xcontext->im_format, NULL, 1, 1, &SHMInfo);
428
429   /* Might cause an error, sync to ensure it is noticed */
430   XSync (xcontext->disp, FALSE);
431   if (!xvimage || error_caught) {
432     GST_WARNING ("could not XvShmCreateImage a 1x1 image");
433     goto beach;
434   }
435   size = xvimage->data_size;
436
437   SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
438   if (SHMInfo.shmid == -1) {
439     GST_WARNING ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
440         size);
441     goto beach;
442   }
443
444   SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0);
445   if (SHMInfo.shmaddr == ((void *) -1)) {
446     GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
447     /* Clean up the shared memory segment */
448     shmctl (SHMInfo.shmid, IPC_RMID, NULL);
449     goto beach;
450   }
451
452   xvimage->data = SHMInfo.shmaddr;
453   SHMInfo.readOnly = FALSE;
454
455   if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
456     GST_WARNING ("Failed to XShmAttach");
457     /* Clean up the shared memory segment */
458     shmctl (SHMInfo.shmid, IPC_RMID, NULL);
459     goto beach;
460   }
461
462   /* Sync to ensure we see any errors we caused */
463   XSync (xcontext->disp, FALSE);
464
465   /* Delete the shared memory segment as soon as everyone is attached.
466    * This way, it will be deleted as soon as we detach later, and not
467    * leaked if we crash. */
468   shmctl (SHMInfo.shmid, IPC_RMID, NULL);
469
470   if (!error_caught) {
471     GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
472         SHMInfo.shmseg);
473
474     did_attach = TRUE;
475     /* store whether we succeeded in result */
476     result = TRUE;
477   } else {
478     GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
479         "Not using shared memory.");
480   }
481
482 beach:
483   /* Sync to ensure we swallow any errors we caused and reset error_caught */
484   XSync (xcontext->disp, FALSE);
485
486   error_caught = FALSE;
487   XSetErrorHandler (handler);
488
489   if (did_attach) {
490     GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
491         SHMInfo.shmid, SHMInfo.shmseg);
492     XShmDetach (xcontext->disp, &SHMInfo);
493     XSync (xcontext->disp, FALSE);
494   }
495   if (SHMInfo.shmaddr != ((void *) -1))
496     shmdt (SHMInfo.shmaddr);
497   if (xvimage)
498     XFree (xvimage);
499   return result;
500 }
501 #endif /* HAVE_XSHM */
502
503 /* bufferpool */
504 static void gst_xvimage_buffer_pool_finalize (GObject * object);
505
506 #define GST_XVIMAGE_BUFFER_POOL_GET_PRIVATE(obj)  \
507    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_XVIMAGE_BUFFER_POOL, GstXvImageBufferPoolPrivate))
508
509 #define gst_xvimage_buffer_pool_parent_class parent_class
510 G_DEFINE_TYPE (GstXvImageBufferPool, gst_xvimage_buffer_pool,
511     GST_TYPE_BUFFER_POOL);
512
513 static const gchar **
514 xvimage_buffer_pool_get_options (GstBufferPool * pool)
515 {
516   static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META,
517     GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT, NULL
518   };
519
520   return options;
521 }
522
523 static gboolean
524 xvimage_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
525 {
526   GstXvImageBufferPool *xvpool = GST_XVIMAGE_BUFFER_POOL_CAST (pool);
527   GstXvImageBufferPoolPrivate *priv = xvpool->priv;
528   GstVideoInfo info;
529   GstCaps *caps;
530
531   if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL))
532     goto wrong_config;
533
534   if (caps == NULL)
535     goto no_caps;
536
537   /* now parse the caps from the config */
538   if (!gst_video_info_from_caps (&info, caps))
539     goto wrong_caps;
540
541   GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT, info.width, info.height,
542       caps);
543
544   priv->im_format = gst_xvimagesink_get_format_from_info (xvpool->sink, &info);
545   if (priv->im_format == -1)
546     goto unknown_format;
547
548   if (priv->caps)
549     gst_caps_unref (priv->caps);
550   priv->caps = gst_caps_ref (caps);
551
552   /* enable metadata based on config of the pool */
553   priv->add_metavideo =
554       gst_buffer_pool_config_has_option (config,
555       GST_BUFFER_POOL_OPTION_VIDEO_META);
556
557   /* parse extra alignment info */
558   priv->need_alignment = gst_buffer_pool_config_has_option (config,
559       GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
560
561   if (priv->need_alignment) {
562     gst_buffer_pool_config_get_video_alignment (config, &priv->align);
563
564     GST_LOG_OBJECT (pool, "padding %u-%ux%u-%u", priv->align.padding_top,
565         priv->align.padding_left, priv->align.padding_left,
566         priv->align.padding_bottom);
567
568     /* do padding and alignment */
569     gst_video_info_align (&info, &priv->align);
570
571     /* we need the video metadata too now */
572     priv->add_metavideo = TRUE;
573   } else {
574     gst_video_alignment_reset (&priv->align);
575   }
576
577   /* add the padding */
578   priv->padded_width =
579       GST_VIDEO_INFO_WIDTH (&info) + priv->align.padding_left +
580       priv->align.padding_right;
581   priv->padded_height =
582       GST_VIDEO_INFO_HEIGHT (&info) + priv->align.padding_top +
583       priv->align.padding_bottom;
584
585   priv->info = info;
586
587   return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config);
588
589   /* ERRORS */
590 wrong_config:
591   {
592     GST_WARNING_OBJECT (pool, "invalid config");
593     return FALSE;
594   }
595 no_caps:
596   {
597     GST_WARNING_OBJECT (pool, "no caps in config");
598     return FALSE;
599   }
600 wrong_caps:
601   {
602     GST_WARNING_OBJECT (pool,
603         "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
604     return FALSE;
605   }
606 unknown_format:
607   {
608     GST_WARNING_OBJECT (xvpool->sink, "failed to get format from caps %"
609         GST_PTR_FORMAT, caps);
610     GST_ELEMENT_ERROR (xvpool->sink, RESOURCE, WRITE,
611         ("Failed to create output image buffer of %dx%d pixels",
612             priv->info.width, priv->info.height),
613         ("Invalid input caps %" GST_PTR_FORMAT, caps));
614     return FALSE;;
615   }
616 }
617
618 /* This function handles GstXImageBuffer creation depending on XShm availability */
619 static GstFlowReturn
620 xvimage_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
621     GstBufferPoolAcquireParams * params)
622 {
623   GstXvImageBufferPool *xvpool = GST_XVIMAGE_BUFFER_POOL_CAST (pool);
624   GstXvImageBufferPoolPrivate *priv = xvpool->priv;
625   GstVideoInfo *info;
626   GstBuffer *xvimage;
627   GstXvImageMeta *meta;
628
629   info = &priv->info;
630
631   xvimage = gst_buffer_new ();
632   meta = gst_buffer_add_xvimage_meta (xvimage, xvpool);
633   if (meta == NULL) {
634     gst_buffer_unref (xvimage);
635     goto no_buffer;
636   }
637
638   if (priv->add_metavideo) {
639     GST_DEBUG_OBJECT (pool, "adding GstVideoMeta");
640     gst_buffer_add_video_meta_full (xvimage, GST_VIDEO_FRAME_FLAG_NONE,
641         GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
642         GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info),
643         info->offset, info->stride);
644   }
645
646   *buffer = xvimage;
647
648   return GST_FLOW_OK;
649
650   /* ERROR */
651 no_buffer:
652   {
653     GST_WARNING_OBJECT (pool, "can't create image");
654     return GST_FLOW_ERROR;
655   }
656 }
657
658 GstBufferPool *
659 gst_xvimage_buffer_pool_new (GstXvImageSink * xvimagesink)
660 {
661   GstXvImageBufferPool *pool;
662
663   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
664
665   pool = g_object_new (GST_TYPE_XVIMAGE_BUFFER_POOL, NULL);
666   pool->sink = gst_object_ref (xvimagesink);
667
668   GST_LOG_OBJECT (pool, "new XvImage buffer pool %p", pool);
669
670   return GST_BUFFER_POOL_CAST (pool);
671 }
672
673 static void
674 gst_xvimage_buffer_pool_class_init (GstXvImageBufferPoolClass * klass)
675 {
676   GObjectClass *gobject_class = (GObjectClass *) klass;
677   GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
678
679   g_type_class_add_private (klass, sizeof (GstXvImageBufferPoolPrivate));
680
681   gobject_class->finalize = gst_xvimage_buffer_pool_finalize;
682
683   gstbufferpool_class->get_options = xvimage_buffer_pool_get_options;
684   gstbufferpool_class->set_config = xvimage_buffer_pool_set_config;
685   gstbufferpool_class->alloc_buffer = xvimage_buffer_pool_alloc;
686 }
687
688 static void
689 gst_xvimage_buffer_pool_init (GstXvImageBufferPool * pool)
690 {
691   pool->priv = GST_XVIMAGE_BUFFER_POOL_GET_PRIVATE (pool);
692 }
693
694 static void
695 gst_xvimage_buffer_pool_finalize (GObject * object)
696 {
697   GstXvImageBufferPool *pool = GST_XVIMAGE_BUFFER_POOL_CAST (object);
698   GstXvImageBufferPoolPrivate *priv = pool->priv;
699
700   GST_LOG_OBJECT (pool, "finalize XvImage buffer pool %p", pool);
701
702   if (priv->caps)
703     gst_caps_unref (priv->caps);
704   gst_object_unref (pool->sink);
705
706   G_OBJECT_CLASS (gst_xvimage_buffer_pool_parent_class)->finalize (object);
707 }
708
709 /* This function tries to get a format matching with a given caps in the
710    supported list of formats we generated in gst_xvimagesink_get_xv_support */
711 gint
712 gst_xvimagesink_get_format_from_info (GstXvImageSink * xvimagesink,
713     GstVideoInfo * info)
714 {
715   GList *list = NULL;
716
717   g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
718
719   list = xvimagesink->xcontext->formats_list;
720
721   while (list) {
722     GstXvImageFormat *format = list->data;
723
724     if (format && format->vformat == GST_VIDEO_INFO_FORMAT (info))
725       return format->format;
726
727     list = g_list_next (list);
728   }
729
730   return -1;
731 }