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