23424e0c4ef8bc6256d07e7e4d620211abf5ba5d
[platform/upstream/gstreamer.git] / sys / ximage / ximagepool.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 "ximagesink.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 GST_DEBUG_CATEGORY_EXTERN (gst_debug_ximagepool);
36 #define GST_CAT_DEFAULT gst_debug_ximagepool
37
38 struct _GstXImageBufferPoolPrivate
39 {
40   GstCaps *caps;
41   GstVideoInfo info;
42   GstVideoAlignment align;
43   guint padded_width;
44   guint padded_height;
45   gboolean add_metavideo;
46   gboolean need_alignment;
47 };
48
49 static void gst_ximage_meta_free (GstXImageMeta * meta, GstBuffer * buffer);
50
51 /* ximage metadata */
52 GType
53 gst_ximage_meta_api_get_type (void)
54 {
55   static volatile GType type;
56   static const gchar *tags[] =
57       { "memory", "size", "colorspace", "orientation", NULL };
58
59   if (g_once_init_enter (&type)) {
60     GType _type = gst_meta_api_type_register ("GstXImageMetaAPI", tags);
61     g_once_init_leave (&type, _type);
62   }
63   return type;
64 }
65
66 const GstMetaInfo *
67 gst_ximage_meta_get_info (void)
68 {
69   static const GstMetaInfo *ximage_meta_info = NULL;
70
71   if (ximage_meta_info == NULL) {
72     ximage_meta_info =
73         gst_meta_register (GST_XIMAGE_META_API_TYPE, "GstXImageMeta",
74         sizeof (GstXImageMeta), (GstMetaInitFunction) NULL,
75         (GstMetaFreeFunction) gst_ximage_meta_free,
76         (GstMetaTransformFunction) NULL);
77   }
78   return ximage_meta_info;
79 }
80
81 /* X11 stuff */
82 static gboolean error_caught = FALSE;
83
84 static int
85 gst_ximagesink_handle_xerror (Display * display, XErrorEvent * xevent)
86 {
87   char error_msg[1024];
88
89   XGetErrorText (display, xevent->error_code, error_msg, 1024);
90   GST_DEBUG ("ximagesink triggered an XError. error: %s", error_msg);
91   error_caught = TRUE;
92   return 0;
93 }
94
95 static GstXImageMeta *
96 gst_buffer_add_ximage_meta (GstBuffer * buffer, GstXImageBufferPool * xpool)
97 {
98   GstXImageSink *ximagesink;
99   int (*handler) (Display *, XErrorEvent *);
100   gboolean success = FALSE;
101   GstXContext *xcontext;
102   GstXImageMeta *meta;
103   gint width, height, align = 15, offset;
104   GstXImageBufferPoolPrivate *priv;
105
106   priv = xpool->priv;
107   ximagesink = xpool->sink;
108   xcontext = ximagesink->xcontext;
109
110   width = priv->padded_width;
111   height = priv->padded_height;
112
113   meta =
114       (GstXImageMeta *) gst_buffer_add_meta (buffer, GST_XIMAGE_META_INFO,
115       NULL);
116 #ifdef HAVE_XSHM
117   meta->SHMInfo.shmaddr = ((void *) -1);
118   meta->SHMInfo.shmid = -1;
119 #endif
120   meta->x = priv->align.padding_left;
121   meta->y = priv->align.padding_top;
122   meta->width = GST_VIDEO_INFO_WIDTH (&priv->info);
123   meta->height = GST_VIDEO_INFO_HEIGHT (&priv->info);
124   meta->sink = gst_object_ref (ximagesink);
125
126   GST_DEBUG_OBJECT (ximagesink, "creating image %p (%dx%d)", buffer,
127       width, height);
128
129   g_mutex_lock (&ximagesink->x_lock);
130
131   /* Setting an error handler to catch failure */
132   error_caught = FALSE;
133   handler = XSetErrorHandler (gst_ximagesink_handle_xerror);
134
135 #ifdef HAVE_XSHM
136   if (xcontext->use_xshm) {
137     meta->ximage = XShmCreateImage (xcontext->disp,
138         xcontext->visual,
139         xcontext->depth, ZPixmap, NULL, &meta->SHMInfo, width, height);
140     if (!meta->ximage || error_caught) {
141       g_mutex_unlock (&ximagesink->x_lock);
142
143       /* Reset error flag */
144       error_caught = FALSE;
145
146       /* Push a warning */
147       GST_ELEMENT_WARNING (ximagesink, RESOURCE, WRITE,
148           ("Failed to create output image buffer of %dx%d pixels",
149               width, height),
150           ("could not XShmCreateImage a %dx%d image", width, height));
151
152       /* Retry without XShm */
153       ximagesink->xcontext->use_xshm = FALSE;
154
155       /* Hold X mutex again to try without XShm */
156       g_mutex_lock (&ximagesink->x_lock);
157
158       goto no_xshm;
159     }
160
161     /* we have to use the returned bytes_per_line for our shm size */
162     meta->size = meta->ximage->bytes_per_line * meta->ximage->height;
163     GST_LOG_OBJECT (ximagesink,
164         "XShm image size is %" G_GSIZE_FORMAT ", width %d, stride %d",
165         meta->size, width, meta->ximage->bytes_per_line);
166
167     /* get shared memory */
168     meta->SHMInfo.shmid =
169         shmget (IPC_PRIVATE, meta->size + align, IPC_CREAT | 0777);
170     if (meta->SHMInfo.shmid == -1)
171       goto shmget_failed;
172
173     /* attach */
174     meta->SHMInfo.shmaddr = shmat (meta->SHMInfo.shmid, NULL, 0);
175     if (meta->SHMInfo.shmaddr == ((void *) -1))
176       goto shmat_failed;
177
178     /* now we can set up the image data */
179     meta->ximage->data = meta->SHMInfo.shmaddr;
180     meta->SHMInfo.readOnly = FALSE;
181
182     if (XShmAttach (xcontext->disp, &meta->SHMInfo) == 0)
183       goto xattach_failed;
184
185     XSync (xcontext->disp, FALSE);
186
187     /* Now that everyone has attached, we can delete the shared memory segment.
188      * This way, it will be deleted as soon as we detach later, and not
189      * leaked if we crash. */
190     shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
191
192     GST_DEBUG_OBJECT (ximagesink, "XServer ShmAttached to 0x%x, id 0x%lx",
193         meta->SHMInfo.shmid, meta->SHMInfo.shmseg);
194   } else
195   no_xshm:
196 #endif /* HAVE_XSHM */
197   {
198     guint allocsize;
199
200     meta->ximage = XCreateImage (xcontext->disp,
201         xcontext->visual,
202         xcontext->depth, ZPixmap, 0, NULL, width, height, xcontext->bpp, 0);
203     if (!meta->ximage || error_caught)
204       goto create_failed;
205
206     /* upstream will assume that rowstrides are multiples of 4, but this
207      * doesn't always seem to be the case with XCreateImage() */
208     if ((meta->ximage->bytes_per_line % 4) != 0) {
209       GST_WARNING_OBJECT (ximagesink, "returned stride not a multiple of 4 as "
210           "usually assumed");
211     }
212
213     /* we have to use the returned bytes_per_line for our image size */
214     meta->size = meta->ximage->bytes_per_line * meta->ximage->height;
215
216     /* alloc a bit more for unexpected strides to avoid crashes upstream.
217      * FIXME: if we get an unrounded stride, the image will be displayed
218      * distorted, since all upstream elements assume a rounded stride */
219     allocsize =
220         GST_ROUND_UP_4 (meta->ximage->bytes_per_line) * meta->ximage->height;
221
222     meta->ximage->data = g_malloc (allocsize + align);
223     GST_LOG_OBJECT (ximagesink,
224         "non-XShm image size is %" G_GSIZE_FORMAT " (alloced: %u), width %d, "
225         "stride %d", meta->size, allocsize, width,
226         meta->ximage->bytes_per_line);
227
228     XSync (xcontext->disp, FALSE);
229   }
230
231   if ((offset = ((guintptr) meta->ximage->data & align)))
232     offset = (align + 1) - offset;
233
234   GST_DEBUG_OBJECT (ximagesink, "memory %p, align %d, offset %d",
235       meta->ximage->data, align, offset);
236
237   /* Reset error handler */
238   error_caught = FALSE;
239   XSetErrorHandler (handler);
240
241   gst_buffer_append_memory (buffer,
242       gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, meta->ximage->data,
243           meta->size + align, offset, meta->size, NULL, NULL));
244
245   g_mutex_unlock (&ximagesink->x_lock);
246
247   success = TRUE;
248
249 beach:
250   if (!success)
251     meta = NULL;
252
253   return meta;
254
255   /* ERRORS */
256 create_failed:
257   {
258     g_mutex_unlock (&ximagesink->x_lock);
259     /* Reset error handler */
260     error_caught = FALSE;
261     XSetErrorHandler (handler);
262     /* Push an error */
263     GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
264         ("Failed to create output image buffer of %dx%d pixels",
265             width, height),
266         ("could not XShmCreateImage a %dx%d image", width, height));
267     goto beach;
268   }
269 #ifdef HAVE_XSHM
270 shmget_failed:
271   {
272     g_mutex_unlock (&ximagesink->x_lock);
273     GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
274         ("Failed to create output image buffer of %dx%d pixels",
275             width, height),
276         ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
277             meta->size));
278     goto beach;
279   }
280 shmat_failed:
281   {
282     g_mutex_unlock (&ximagesink->x_lock);
283     GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
284         ("Failed to create output image buffer of %dx%d pixels",
285             width, height), ("Failed to shmat: %s", g_strerror (errno)));
286     /* Clean up the shared memory segment */
287     shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
288     goto beach;
289   }
290 xattach_failed:
291   {
292     /* Clean up the shared memory segment */
293     shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
294     g_mutex_unlock (&ximagesink->x_lock);
295
296     GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
297         ("Failed to create output image buffer of %dx%d pixels",
298             width, height), ("Failed to XShmAttach"));
299     goto beach;
300   }
301 #endif
302 }
303
304 static void
305 gst_ximage_meta_free (GstXImageMeta * meta, GstBuffer * buffer)
306 {
307   GstXImageSink *ximagesink;
308
309   ximagesink = meta->sink;
310
311   GST_DEBUG_OBJECT (ximagesink, "free meta on buffer %p", buffer);
312
313   /* Hold the object lock to ensure the XContext doesn't disappear */
314   GST_OBJECT_LOCK (ximagesink);
315   /* We might have some buffers destroyed after changing state to NULL */
316   if (ximagesink->xcontext == NULL) {
317     GST_DEBUG_OBJECT (ximagesink, "Destroying XImage after XContext");
318 #ifdef HAVE_XSHM
319     /* Need to free the shared memory segment even if the x context
320      * was already cleaned up */
321     if (meta->SHMInfo.shmaddr != ((void *) -1)) {
322       shmdt (meta->SHMInfo.shmaddr);
323     }
324 #endif
325     goto beach;
326   }
327
328   g_mutex_lock (&ximagesink->x_lock);
329
330 #ifdef HAVE_XSHM
331   if (ximagesink->xcontext->use_xshm) {
332     if (meta->SHMInfo.shmaddr != ((void *) -1)) {
333       GST_DEBUG_OBJECT (ximagesink, "XServer ShmDetaching from 0x%x id 0x%lx",
334           meta->SHMInfo.shmid, meta->SHMInfo.shmseg);
335       XShmDetach (ximagesink->xcontext->disp, &meta->SHMInfo);
336       XSync (ximagesink->xcontext->disp, FALSE);
337       shmdt (meta->SHMInfo.shmaddr);
338       meta->SHMInfo.shmaddr = (void *) -1;
339     }
340     if (meta->ximage)
341       XDestroyImage (meta->ximage);
342   } else
343 #endif /* HAVE_XSHM */
344   {
345     if (meta->ximage) {
346       XDestroyImage (meta->ximage);
347     }
348   }
349
350   XSync (ximagesink->xcontext->disp, FALSE);
351
352   g_mutex_unlock (&ximagesink->x_lock);
353
354 beach:
355   GST_OBJECT_UNLOCK (ximagesink);
356
357   gst_object_unref (meta->sink);
358 }
359
360 #ifdef HAVE_XSHM
361 /* This function checks that it is actually really possible to create an image
362    using XShm */
363 gboolean
364 gst_ximagesink_check_xshm_calls (GstXImageSink * ximagesink,
365     GstXContext * xcontext)
366 {
367   XImage *ximage;
368   XShmSegmentInfo SHMInfo;
369   size_t size;
370   int (*handler) (Display *, XErrorEvent *);
371   gboolean result = FALSE;
372   gboolean did_attach = FALSE;
373
374   g_return_val_if_fail (xcontext != NULL, FALSE);
375
376   /* Sync to ensure any older errors are already processed */
377   XSync (xcontext->disp, FALSE);
378
379   /* Set defaults so we don't free these later unnecessarily */
380   SHMInfo.shmaddr = ((void *) -1);
381   SHMInfo.shmid = -1;
382
383   /* Setting an error handler to catch failure */
384   error_caught = FALSE;
385   handler = XSetErrorHandler (gst_ximagesink_handle_xerror);
386
387   /* Trying to create a 1x1 ximage */
388   GST_DEBUG ("XShmCreateImage of 1x1");
389
390   ximage = XShmCreateImage (xcontext->disp, xcontext->visual,
391       xcontext->depth, ZPixmap, NULL, &SHMInfo, 1, 1);
392
393   /* Might cause an error, sync to ensure it is noticed */
394   XSync (xcontext->disp, FALSE);
395   if (!ximage || error_caught) {
396     GST_WARNING ("could not XShmCreateImage a 1x1 image");
397     goto beach;
398   }
399   size = ximage->height * ximage->bytes_per_line;
400
401   SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
402   if (SHMInfo.shmid == -1) {
403     GST_WARNING ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
404         size);
405     goto beach;
406   }
407
408   SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0);
409   if (SHMInfo.shmaddr == ((void *) -1)) {
410     GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
411     /* Clean up the shared memory segment */
412     shmctl (SHMInfo.shmid, IPC_RMID, NULL);
413     goto beach;
414   }
415
416   ximage->data = SHMInfo.shmaddr;
417   SHMInfo.readOnly = FALSE;
418
419   if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
420     GST_WARNING ("Failed to XShmAttach");
421     /* Clean up the shared memory segment */
422     shmctl (SHMInfo.shmid, IPC_RMID, NULL);
423     goto beach;
424   }
425
426   /* Sync to ensure we see any errors we caused */
427   XSync (xcontext->disp, FALSE);
428
429   /* Delete the shared memory segment as soon as everyone is attached.
430    * This way, it will be deleted as soon as we detach later, and not
431    * leaked if we crash. */
432   shmctl (SHMInfo.shmid, IPC_RMID, NULL);
433
434   if (!error_caught) {
435     GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
436         SHMInfo.shmseg);
437
438     did_attach = TRUE;
439     /* store whether we succeeded in result */
440     result = TRUE;
441   } else {
442     GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
443         "Not using shared memory.");
444   }
445
446 beach:
447   /* Sync to ensure we swallow any errors we caused and reset error_caught */
448   XSync (xcontext->disp, FALSE);
449
450   error_caught = FALSE;
451   XSetErrorHandler (handler);
452
453   if (did_attach) {
454     GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
455         SHMInfo.shmid, SHMInfo.shmseg);
456     XShmDetach (xcontext->disp, &SHMInfo);
457     XSync (xcontext->disp, FALSE);
458   }
459   if (SHMInfo.shmaddr != ((void *) -1))
460     shmdt (SHMInfo.shmaddr);
461   if (ximage)
462     XDestroyImage (ximage);
463   return result;
464 }
465 #endif /* HAVE_XSHM */
466
467 /* bufferpool */
468 static void gst_ximage_buffer_pool_finalize (GObject * object);
469
470 #define GST_XIMAGE_BUFFER_POOL_GET_PRIVATE(obj)  \
471    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_XIMAGE_BUFFER_POOL, GstXImageBufferPoolPrivate))
472
473 #define gst_ximage_buffer_pool_parent_class parent_class
474 G_DEFINE_TYPE (GstXImageBufferPool, gst_ximage_buffer_pool,
475     GST_TYPE_BUFFER_POOL);
476
477 static const gchar **
478 ximage_buffer_pool_get_options (GstBufferPool * pool)
479 {
480   static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META,
481     GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT, NULL
482   };
483
484   return options;
485 }
486
487 static gboolean
488 ximage_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
489 {
490   GstXImageBufferPool *xpool = GST_XIMAGE_BUFFER_POOL_CAST (pool);
491   GstXImageBufferPoolPrivate *priv = xpool->priv;
492   GstVideoInfo info;
493   GstCaps *caps;
494
495   if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL))
496     goto wrong_config;
497
498   if (caps == NULL)
499     goto no_caps;
500
501   /* now parse the caps from the config */
502   if (!gst_video_info_from_caps (&info, caps))
503     goto wrong_caps;
504
505   GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT, info.width, info.height,
506       caps);
507
508   /* keep track of the width and height and caps */
509   if (priv->caps)
510     gst_caps_unref (priv->caps);
511   priv->caps = gst_caps_ref (caps);
512
513   /* check for the configured metadata */
514   priv->add_metavideo =
515       gst_buffer_pool_config_has_option (config,
516       GST_BUFFER_POOL_OPTION_VIDEO_META);
517
518   /* parse extra alignment info */
519   priv->need_alignment = gst_buffer_pool_config_has_option (config,
520       GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
521
522   if (priv->need_alignment) {
523     gst_buffer_pool_config_get_video_alignment (config, &priv->align);
524
525     GST_LOG_OBJECT (pool, "padding %u-%ux%u-%u", priv->align.padding_top,
526         priv->align.padding_left, priv->align.padding_left,
527         priv->align.padding_bottom);
528
529     /* do padding and alignment */
530     gst_video_info_align (&info, &priv->align);
531
532     /* we need the video metadata too now */
533     priv->add_metavideo = TRUE;
534   } else {
535     gst_video_alignment_reset (&priv->align);
536   }
537
538   /* add the padding */
539   priv->padded_width =
540       GST_VIDEO_INFO_WIDTH (&info) + priv->align.padding_left +
541       priv->align.padding_right;
542   priv->padded_height =
543       GST_VIDEO_INFO_HEIGHT (&info) + priv->align.padding_top +
544       priv->align.padding_bottom;
545
546   priv->info = info;
547
548   return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config);
549
550   /* ERRORS */
551 wrong_config:
552   {
553     GST_WARNING_OBJECT (pool, "invalid config");
554     return FALSE;
555   }
556 no_caps:
557   {
558     GST_WARNING_OBJECT (pool, "no caps in config");
559     return FALSE;
560   }
561 wrong_caps:
562   {
563     GST_WARNING_OBJECT (pool,
564         "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
565     return FALSE;
566   }
567 }
568
569 /* This function handles GstXImageBuffer creation depending on XShm availability */
570 static GstFlowReturn
571 ximage_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
572     GstBufferPoolAcquireParams * params)
573 {
574   GstXImageBufferPool *xpool = GST_XIMAGE_BUFFER_POOL_CAST (pool);
575   GstXImageBufferPoolPrivate *priv = xpool->priv;
576   GstVideoInfo *info;
577   GstBuffer *ximage;
578   GstXImageMeta *meta;
579
580   info = &priv->info;
581
582   ximage = gst_buffer_new ();
583   meta = gst_buffer_add_ximage_meta (ximage, xpool);
584   if (meta == NULL) {
585     gst_buffer_unref (ximage);
586     goto no_buffer;
587   }
588   if (priv->add_metavideo) {
589     GST_DEBUG_OBJECT (pool, "adding GstVideoMeta");
590     /* these are just the defaults for now */
591     gst_buffer_add_video_meta_full (ximage, GST_VIDEO_FRAME_FLAG_NONE,
592         GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
593         GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info),
594         info->offset, info->stride);
595   }
596   *buffer = ximage;
597
598   return GST_FLOW_OK;
599
600   /* ERROR */
601 no_buffer:
602   {
603     GST_WARNING_OBJECT (pool, "can't create image");
604     return GST_FLOW_ERROR;
605   }
606 }
607
608 GstBufferPool *
609 gst_ximage_buffer_pool_new (GstXImageSink * ximagesink)
610 {
611   GstXImageBufferPool *pool;
612
613   g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), NULL);
614
615   pool = g_object_new (GST_TYPE_XIMAGE_BUFFER_POOL, NULL);
616   pool->sink = gst_object_ref (ximagesink);
617
618   GST_LOG_OBJECT (pool, "new XImage buffer pool %p", pool);
619
620   return GST_BUFFER_POOL_CAST (pool);
621 }
622
623 static void
624 gst_ximage_buffer_pool_class_init (GstXImageBufferPoolClass * klass)
625 {
626   GObjectClass *gobject_class = (GObjectClass *) klass;
627   GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
628
629   g_type_class_add_private (klass, sizeof (GstXImageBufferPoolPrivate));
630
631   gobject_class->finalize = gst_ximage_buffer_pool_finalize;
632
633   gstbufferpool_class->get_options = ximage_buffer_pool_get_options;
634   gstbufferpool_class->set_config = ximage_buffer_pool_set_config;
635   gstbufferpool_class->alloc_buffer = ximage_buffer_pool_alloc;
636 }
637
638 static void
639 gst_ximage_buffer_pool_init (GstXImageBufferPool * pool)
640 {
641   pool->priv = GST_XIMAGE_BUFFER_POOL_GET_PRIVATE (pool);
642 }
643
644 static void
645 gst_ximage_buffer_pool_finalize (GObject * object)
646 {
647   GstXImageBufferPool *pool = GST_XIMAGE_BUFFER_POOL_CAST (object);
648   GstXImageBufferPoolPrivate *priv = pool->priv;
649
650   GST_LOG_OBJECT (pool, "finalize XImage buffer pool %p", pool);
651
652   if (priv->caps)
653     gst_caps_unref (priv->caps);
654   gst_object_unref (pool->sink);
655
656   G_OBJECT_CLASS (gst_ximage_buffer_pool_parent_class)->finalize (object);
657 }